[ azzpoz @ 15.12.2013. 11:08 ] @
Znam da prilikom nasljeđivanja, ne "dobijamo" kon(/de)struktor, operatore super klase, a kod kompozicije to imamo za primjenu...

Interesuje me razlika, kada bi bilo praktičnije koristiti nasljeđivanje, odnosno kompoziciju u klasama?
[ glorius @ 15.12.2013. 13:47 ] @
Mislim da nema nekog generalnog pravila ali, kao sto kazu mnoge knjizice, treba preferirati kompoziciju.

Odlican primer gde kompozicija potpomaze dizajn je Bridge design pattern koji koristi kompoziciju da bi 'razbio' eksponencijalnu eksploziju klasa.
Jedan od primera za to je da ako imas kontrole u aplikaciji, npr. baznu klasu Widget i iz nje izvedene PushButton, Label, CheckBox i ako zelis da ti app radi na razlicitim sistemima (Windows, Linux, Mac) onda bi morao da imas drugaciji kod za iscrtavanje. Jedna od ideja je da, ako posmatramo Label, imas LabelWin, LabelLinux, LabelMac izvedene iz Label. Isto bi tako iz svih klasa koji predstavljaju konkretne widgete nasledjivao po 3 klase. Eksponencijalna eksplozija se da primetiti kada sad trebas da dodas novi Widget ili novi sistem (Netware npr.)...
Bridge pattern onda koristi kompoziciju tako sto izdvaja hijerarhiju widgeta sa jedne strane i hijerarhiju operativnih sistema (bazna klasa Platform i iz nje izvedene Windows, Mac i Linux). Widget SADRZI pointer na Platform instancu u zavisnosti na kojem smo sistemu i poziva metode platform instance za iscrtavanje.
Detaljnije o ovome mozes anci na netu...

Iz mog nekog iskustva, prvi nagovestaj koriscenja kompozicije je situacija kada ti zatreba visestruko nasledjivanje. Npr. ako imas objekte u igri, neki od njih su Renderable a neki nisu, na neke se apply-uje kolizija a na neke ne, onda bi mogli da izdvojimo one koji su i Renderable i Collidable. Npr. neka to bude klasa Actor. Logicno bi bilo da se nasledi iz Renderable i Collidable. Razlika izmedju nasledjivanja i kompozicije je u tome sto je, mozda vec i znas, nasledjena klasa 'is' Renderable a kod kompozicije 'has' Renderable. Po meni je ovde bolje imati kompoziciju, pointer na Renderable i na Collidable i onda inicijalizujes obe instance u zavisnosti da li ce objekat imati osobine da moze da se iscrtava i da li ce da ucestvuje u koliziji (npr. Background je renderable ali nije collidable, triggeri neki na mapi su collidable ali nisu renderable). Jeste kontradiktorno to sto je objekat Renderable i Collidable 'is' -> nasledjivanje, suprotno tome da sadrzi Renderable i Collidable u sebi ali ti kompozicija u ovom slucaju cak daje mogucnost da u runtime podesavas i menjas Renderable i Collidable osobine (objekat postane duh u igri u jednom trenutku npr. :) i samo odradis delete m_pCollidable ).
[ deerbeer @ 15.12.2013. 13:58 ] @
Kompozicija je bolja i zbog pisanja automatskih unit testova.
[ glorius @ 15.12.2013. 14:00 ] @
Moze li malo detaljnije to oko automatskih unit testova?
[ glorius @ 15.12.2013. 14:41 ] @
Ako te interesuje malo vise o Design patternima, preporucujem knjigu "Design Patterns - Elements of Reusable Object-Oriented Software" gde ces, kroz ucnje design patterna, skapirati vremenom kada da koristis kompoziciju a kada nasledjivanje.
[ X Files @ 15.12.2013. 16:09 ] @
Da, to je bila moja prva knjiga o Design patternima.

U njoj ima nešto o pitanju iz naslova:
Inheritance versus Composition
"Favor object composition over class inheritance"

Progugluj malo. A bio je i prevod u našim knjižarama.


Sećam se i "Program to an interface, not an implementation".
[ glorius @ 15.12.2013. 16:44 ] @
Postoji jos jedna koja je bas interesantno odradjena "Design Patterns Explained". Iskreno, ne znam koliko sam sve skapirao iz knjige ali je akcenat bas na tome da se razmislja na skroz high levelu (interfejsi) dok se dizajnira aplikacija i da nema, skoro, ni potrebe razmisljati o konkretnim (izvedenim) klasama vec da je key za dizajn pravilna kombinacija i odabir design patterna.

I jos jedna 'Modern C++ Design Generic Programming and Design Patterns Applied'.
[ deerbeer @ 15.12.2013. 18:40 ] @
Citat:
glorius: Moze li malo detaljnije to oko automatskih unit testova?


Pisanje testova je dosta olaksano. Setup mock objekata koje ces da injektujes u objekte/klase kroz neki set ili konstuktor koje testiras laksi je
od istog kada imas podugacku inheritance listu , onda zapadas u probleme testiranje baznih klasa pristupom nekih metoda (protected private) itd..
O visestrukom nasledjivanju da ne pricam.

Pri tom pozeljno je da objekti koji sastavljaju drugi ipak budu u formi nekog interfejsa cime prvo razbijas jaku povezanost objekata( decoupling),
a u mock klasi impementiras interfejs tj. samo mozda neke metode koje su relevantne za jedan unit test.

Ako vec kompozija nije pozeljna u datoj situaciji onda mozda template pattern pa override apstraktnih metoda koje klasa pruza,
pa bi mock klasa trebala da overajduje iste metode kroz nasledjivanje kao i implementorska.