OO Design

11 отговора 427 прегледа
#1

OO Design

Zdraveite,

ot niakolko meseca tarsia dobroto reshenie na edin problem. sas sigurnost vseki go e reshil po niakakav nachin, no dosega ne sam vidial niakoi da go e napravil kachestveno. ako niakoi ot vas ima naistina dobra koncepcia, molia da ia spodeli. eto go i problema:

PRIMERNA POSTANOVKA
neka profesia da e uprajniavana ot choveka deinost, s cel pechelene na pari. edin chovek moje da ima 0, 1 ili niakolko profesii. samite profesii bivat nai-razlichni, a i po definicia ne sa kraino zatvoreno mnojestvo, t.e. tai kato vav vseki moment se sazdavat novi profesii, ne moje da se razchita na predvaritelen palen spisak na vsichki profesii.

i taka, na slednite vaprosi, vseki chovek moje da otgovori:
1. ti imash li profesia (da/ne)?
2. kakva (kakvi) sa tvoite profesii?
3. ti takav (konkretna profesia) li si?

eto niakoi (nai-chesto sreshtani) podhodi:

1. inheritance - naistina slab podhod v sluchaia
// obsht class za vsichki
class Man {
String name = null;
String egn = null;
}

class Architect extends Man {
int designedBuildings = -1;
}

class Mechanic extends Man {
int repairedAutos = -1;
}

class Test {
public static void main (String[] args) {
Man man = getMan(); // vzimash go ot kade da e, ne e vajno

//1vi vapros
if (man instanceof Architect || man instanceof Mechanic) {
// poluchavame otgovora
}

//2ri vapros - problem, nereshim chrez tozi podhod. ako imame
// spisak na vsichki hora, moje da tarsim po EGN, i da trupame
// profesiite v spisak, taka shte stane

//3ti vapros: architekt li e?
if (man instanceof Architect) {
// poluchavame otgovor
}
}
}

tova e ujasno. tuk profesiite ne moje da ne sa kraen broi, i triabva da sa ni predvaritelno izvestni, inache ne mojem da poluchim otgovora na 1vi vapros. otgovora na 2ri zavisi ot podhoda pri sahranenieto na dannite. a otgovora na 3ti izglejda prividno dobre. naistina ujasnoto v sluchaia sa slednite 2 neshta:
- niama vrazka m/u otdelnite profesii na choveka i samia chovek. ako edin chovek ima 3 profesii i si smeni imeto, imame problem. problem ima, i ako choveka pridobie nova profesia.
- nie ne pitame choveka nishto. nie prosto go sravniavame sas shabloni. a po zadanie triabva da go pitame.

2. Composition (kato che li po-dobar)

interface Proffesion {
// neshto si
}

class Architect implements Proffesion {
int designedBuildings = -1;
}

class Mechanic implements Proffesion {
int repairedAutos = -1;
}

class Man {
String name = null;
String egn = null;
Vector proffesions = null;

void addProffesion (Proffesion newProf) {
proffesions.add(newProf);
}

Proffesion[] getProfessions () {
Proffesion[] result = new Proffesion[proffesions.size];
proffesions.copyInto(result);
return result;
}

boolean hasProffesion () {
boolean result = false;
if (0 < proffesions.size) {
result = true;
}
return result;
}

boolean is (Proffesion prof) {
boolean result = false;
Proffesion[] currentProfs = getProfessions();
for (int counter = 0; counter < currentProfs.length; counter ++) {
if (currentProfs[counter].getClass().getName().equals(prof..getClass().getName()) {
result = true;
}
}
}
}

class Test {
public static void main (String[] args) {
Man man = getMan(); // vzimash go ot kade da e, ne e vajno

//1vi vapros
man.hasProffesion();

//2ri vapros
Proffesion[] allProfs = man.getProffesions();

//3ti vapros
man.is(new Architect());
}
}

otgovorite na parvite dva vaprosa se davat, po moi kriterii, dostatachno dobre. otgovora na 3tia, obache se postiga chrez sravnenie s object, koeto ne e korektno, spored zadanieto koeto postavih v nachaloto. ne e korektno i spored realnia sviat, ot koito idva zadanieto. nie iskame da pitame "ti takav li si po profesia?", a v konkretnata realizacia pitame "ti imash li profesia kato tazi?". ako razlikata ne e iasna, tia e razlikata m/u

man.getProffesions()[2].getClass().getName().equals(new Architekt().getClass.getName)
i
man.getProffesions()[2] instanceof Architekt

dokato v parvia sluchai sravniavame stringove, koito harakterizirat obektite, i imame edin paraziten objet (new Architekt()), vav vtoria, vsichko e mnogo chisto - sravniavame konkretna profesia na choveka s abstrakcia (class/type) na tarsenata ot nas profesia - kakto v realnia sviat - "ti architekt li si", koeto s drugi dumi e "ti imash li m/u tvoite konkretni profesii, takava, koiato izhojda ot abstrakciata, class-a architekt?"

problemat mi da izpolzvam vtoria podhod, e che ne moje (ili ne znam kak?) da predam Type kato parametar na method, za da moga da pitam choveka - ti imash li takava profesia, a ako vzema profesiite i edna po edna gi sravniavam izvan class-a Man, shte izleze, che ne pitam choveka, a pravia nezavisimo prouchvane. koeto e tapo.

i taka : ) kak se realizira otgovarianeto na 3tia vapros?

blagodaria

Отговор
в отговор на lexo #2

Re: OO Design

Защо не:

class Profession {
private Profession() {}

public static final Profession ARHITECT = new Profession();
public static final Profession MECHANIC = new Profession();
}

в смисъл - имаш ли наистина специфичен код за всяка професия. Във тия всички въпроси, които питаш няма такова нещо - има само дали човек има дадена професия.

Иначе - друго което ми идва наум да си направиш така както е:
boolean is(Class professionClass) {
for (int i = 0; i < professions.length) {
if (profession instanceof professionClass) {
return true;
}
}
return false;
}

class Test {
void test() {
m.is(Architect.class);
}
}

Това е почти същото като твоето де.
Н знам - според мене важното е дали има смисъл всяка професия да е отделен клас? Т.е. имаш ли нещо, което отличава една професия от друга (примерно да има метод в Profession.doSomething()). Ако такъв метод нямаш (или всичко, което имаш е например - getName()) просто няма нужда от класове и интерфейси за професии.

Отговор
в отговор на josarjan #3

Re: OO Design

mersi za otgovora

1. - (moje da ne sam te razbral, no) triabva da ima otdelen class za vsiaka profesia. samia primer s profesiite e obobshtenie na niakolko sluchaia, v koito sam se sreshtal s tozi problem. a i vajna chast ot zadachata e, che triabva da moje da se dobaviat novi profesii i te da se svarzvat s horata, bez da se prekompilirat veche sashtestvuvashti class-ove. koeto znachi, che ne moje da se napravi statichen spisak na otdelnite vidove profesii.

2. da, pak se opira do class object, koito pak se vzima ot object instance na dadenia class, i t.n., osven tova instanceof se pravi s type, a ne s class object, ma tva ne e mnogo vajno

Редактирано от lexo на

Отговор
в отговор на lexo #4

Re: OO Design

1. Това се прави точно с комосишън, като класа човек има лист или някаква друга колекция от базовия клас/интерфейс на професиите.

2. Принципно си е н/м връзка, така че виж да не ти трябва и примерно кои точно хора упражняват някоя професия, защото го няма сред въпросите, които те интересуват. Ако има "въпроси" и от 2те страни, т.е с изходна точка човек или професия, може евентуално да създадеш клас, които репресентира самта връзка, и после всяка от страните държи колекция с обекти от него.
Ако наистина всички въпроси са само тези 3те, най-добре е вариант 1.
Според мен.

Отговор
в отговор на lexo #5

Re: OO Design

Ot tova koeto predlagash vtoroto opredeleno e po-dobro.

Mozhesh da promenish Man.is() taka:

boolean is (Class prof) {
boolean result = false;
Proffesion[] currentProfs = getProfessions();
for (int counter = 0; counter < currentProfs.length; counter ++) {
if (prof.isInstance(currentProfs[counter])) {
result = true;
}
}
return result;
}

man.is(Architect.class);

Taka ne se syzdavat izlishni obekti.
Ot druga starna, ne e zadylzhitelno da tyrsish reshenie s naslediavane. Vsichko se opredelia ot iziskvaniata na konkretnia problem a ne ot realnia sviat.
Tova e edna mnogo interesna statia na tema OO design, koiato shte te nakara dosta da se zamislish dali podhoda ti e pravilen:

[линк]

Vyobshte tozi avtor ima mnogo interesni idei:
[линк]

Отговор
в отговор на antijb #6

Re: OO Design

Още един фен на "Uncle" Bob :)).

Както и да е - аз затова горе предложих просто някакви статични променливи. Може даже и стрингове.
Просто за така поставената задача - да се проверява дали даден човек притежава професия и да може да се добавят / махат професии е напълно достатъчно да имаш един Set, в който да бухаш String обекти.

Ако има и някакво поведение, асоциирано с тия професии - тогава има смисъл от общ интерфейс, класове, т.н.

Отговор
в отговор на lexo #7

Re: OO Design

Извинявай - може да не съм разбрал добре задачата.
Но ако проблема е:
1. Имаш хора
2. Всеки човек има професии
3. Искаш да питаш човек дали има дадена професия
4. Искаш да видиш всички професии за човек
5. Искаш да можеш да конфигурираш човек, като му добавяш/махаш професии.

Е, за тия неща всичко, което ти трябва е клас Man , в който има Set от String със професии.
Дай повече детайли - примерно по-какво една професия се отличава от друга (освен по име, description, etc).

Отговор
в отговор на josarjan #8

more info

blagodaria za postingite

tova s choveka i profesiite go izmislih s cel problema da e po-iasen.

tova e realna zadacha, zasiagashta tozi problem:

basa danni s companii (imena, adresi, contacti i t.n.).

vavejda se dadena firma. v posledstvie se okazva, che tova ne e prosto firma, a e firma prevozvach. kam neia se dobaviat prevozni sredstva i t.n., kakto si mu e reda. sled tova se okazva, che tia e i firma targovec, i kam neia se vavejdat stokite koito predlaga.

dotuk dobre. oshte na design level znaeme za tezi dve raznovidnosti na firmata, i sme gi predvidili po niakakav nachin. software-a e predaden, klienta si raboti, i v tozi moment se okazva, che ima oshte 1 vid firmi - hamalski uslugi. za tiah se definira spisak usluga->tarifa.
pri tova na veche sashtestvuvashta firma moje da i se zadade i takav profil. triabva da mojesh da obrabotvash vsichki firmi kato firmi (obsht profil), i vsiaka kategoria po otdelno (targovci, prevozvachi i t.n.). t.e. razpolagash sas spisak firmi, spisak targovci i t.n., kato vseki chlen ot vseki spisak moje da se obrabotva spored spisaka v koito e i t.n. periodichno iznikva neobhodimost ot vavejdane na novi tipove firmi i obrabotkata na neobhodimata za tova informacia.

estestveno, dobavianeto na code e dobre da stane maximalno s dobaviane na novi class-ove i minimalno s dobaviane na code v sashtestvuvashti. "modificirane na sashtestvuvasht code" e mrasna duma.

tai kato problema ne beshe definiran na design-level, niama da spomenavam tekushtoto reshenie, zashtoto to raboti blagodarenie na 2-3 edri krapki, napraveni sled parvia sluchai na "abe, tia tazi firma vsashnost pravi i tova, ma nie tova mai ne sme go kazali predvaritelno..." t.e., nastoiashtia code vaobshte ne e za pokazvane. v tozi smisal, obmisliam redesign, no moga da si pozvolia da go napravia samo vednaj, taka che se staraia, da e nai-blizko do optimalnoto.

cheta dialogovata statia, shte pregledam i drugata, blagodaria. sega po praznicite moje da ostane vreme za preosmisliane.

ako niakoi ima ideia s ogled na po-detailnata zadacha, shte shte mi e mn. interesno da i vidia

pozdravi

Отговор
в отговор на lexo #9

Re: more info

Е така кажи, доста по-ясно става за какво точно питаш.
Моето предложение за рещение на проблема е следното:
1. Трябва ти една таблица за фирмите с общатата за всички информация, име адрес, телефон и т.н.
2. За всеки тип фирми търговски, хамалски, .. ти трябва отделна таблица с свойствените за тях характеристики.
3. Имаш нужда от една таблица, в която са изброни видовете дейности, с имената на съответните таблици и ид. Ако добавяш нов вид дейност създаваш новата таблица "производтсвена дейност" и добавяш един ред тук.
4. Накрая идва таблица, с колони "Номер фирма" "Вид дейност". Ако една фирма има 3 дейности има 3 записа с нея в тази таблица, за всяка дейност по-отделно.

От там вече как ще се представя в жава важи това, което писах и по-горе. Всички видовве дейности наследяват от клас или интерфейс дейност, който си знае таблицата. Обекта фирма, който всъщност има само общите информации има колекция с дейности и методи, добави дейност, и кажи си всичките дейности.
Като се окаже, че трябва да се добавя несъществуваща дейност към съществуваща фирма викаш метода добави дейност(примерно статичен в клас дейност), който създава новата таблица, нанася името и в таблица 3. След което създаваш обекта: дейност = нова хамалска_дейниост; и извикваш метода добави дейност на фирмата с него, която добава дейността в колекцията си, прочита коя е таблицата на дейността и ид/то и и добавя съотвтния ред в 4.

Това е според мен.

Отговор
в отговор на lexo #10

Re: more info

OK.
Togawa kakwo prechi da imash Map ot (String, Object), kydeto String e imeto na dejnostta (Activity), a Object e class-a, kojto implement-wa taja dejnost. I da tyrsish wytre po ime.

class Company {
private final Map activities = new HashMap();

void addActivity(Activity activity) {
this.activities.put(activity.getName(), activity);
}

void removeActivity(String activityName){
this.activities.remove(activityName);
}

void is(String activityName) {
return this.activities.containsKey(activityName);
}

Object as(String activityName) {
return this.activities.get(activityName);
}
}

abstract class Activity {
private final String name;

protected Activity(String name) {
this.name = name;
}

String getName() {
return this.name;
}
}

class Seller extends Activity {
Seller() {
super("seller");
}

int getGoodsSelled() {
// bla, bla, bla
}
}

class Transporter extends Activity {
Transporter() {
super("transporter");
}

int getCarsAvailable() {
// bla, bla, bla
}
}

void test(Company c) {
if (!c.is("seller")) {
System.out.println("not a seller");
}
Seller seller = (Seller) c.as("seller");
System.out.println("Goods selled: " + seller.getGoodsSelled());

if (!c.is("transporter")) {
System.out.println("not a transporter");
}
Transported transporter = (Transporter) c.as("transporter");
System.out.println("Cars available: " + transported.getCarsAvailable());
}


Ami towa e, koeto mi hrumwa. Trjabwa da widish kak shte gi map-nesh kym DB.

Отговор
в отговор на lexo #12

Re: OO Design

Mislq 4e "Factory Pattern" moje da ti pomogne w slu4aq ,ima go opisan w GoF

Отговор