Objektumorientált szoftvertervezés - 2. előadásObjektumorientált tervezési heurisztikák
Letöltés PDF-ként
Osztályok tervezése
- Az attribútumok mindig legyenek privátok, a hozzáférést getter/setter-rel biztosítjuk, így megmarad a konzisztencia
- protected, public, package láthatóság sérti az információrejtés elvét
- kötődés alakul ki → erősebb csatoltság lesz :(
- year, month, day értékkészleteire figyelnünk kéne, ha publikusak akkor nem tudjuk őket felügyelni
- Ne használjuk másik osztály nempublikus tagjait
- ha nagyon egybefüggenek egyen belőlük egy osztály → erős csatolás helyett erős kohézió lesz, ami jó
- Minimalizáljuk a publikus metódusok számát
- feleslegesen semmi ne legyen publikus, ISP egy megvalósítása
- Implementáljuk a sztenderd metódusokat
- string-é alakítás, összehasonlítás, hash kód generálás
- Egy osztály ne függjön az őt használó osztályoktól, azaz saját leszármazottjától se
- Egy osztály csak egy absztrakcióval rendelkezzen
- ha keverednek az absztrakciós szintek, daraboljuk több részre
- rossz helyen allokált felelősségek is az absztrakciós szintek keveredéséhez vezethetnek
- kivétel: DRY elv sérülését kerüljük el → Visitor, Strategy
- Az összetartozó adatot és viselkedést tartsuk egy helyen, azaz egyetlen közös osztályban
- körkörös viselkedést is érdemes egy osztályba vonni
- A metódusok használjanak minél több attribútumot és metódust a saját osztályukból
- kerüljük az "isten osztályokat", daraboljuk többfele
- kivétel: adatbáziskezelés, és hálózati lekérés osztályok
- A viselkedést modellezzük, ne a szerepeket
Felelősségek
- A felelősségeket egyenletesen osszuk szét, ne legyenek se túl sok, se túl kevés felelősséggel rendelkező osztály
- Kerüljük az isten-osztályokat
- Kerüljük a csak adattárolásra használt osztályokat
- Kerüljük azokat az osztályokat, amelyeknek függvényeknek kellene lenniük
- legyen gyanús, ha egy osztálynak egy függvénye van, vagy az egész osztály neve valamilyen igét tartalmaz
- Modellezzük a valódi világ működését
- mint a valóságban a mozdony húzza az első vagont, ami a másodikat, stb
- Modellezzünk a megfelelő absztrakciós szinten
- azaz a való világot egyszerűsítsük
- Modellezésnél maradjunk a rendszer határain belül
- pl pénzkiadó automatának nem része az ember, csak interfésze van
- Mindig a nézet függjön a modelltől, sosem a modell a nézettől
- pull modell - grafika folyamatosan lekérdezi a modell állapotát, újrarajzoljuk x időnként a UI-t
- push modell - a modell értesíti a grafikát, ha valami változott, csak ténylegesen szűkséges esetben frissítjük
- modellnek kell a grafikát ismernie (ez egy interface-el leválasztható)
Asszociációk
- cél: spagetti kód elkerülése
- Minimalizáljuk az együttműködő osztályok számát
- ISP, DIP segítségül hívható
- Minimalizáljuk az együttműködő osztályok között használt metódusok számát
- Osszuk szét a felelősségeket a tartalmazás mentén
- tartalmazott komponensekből jöjjön létre a tartalmazó osztály
- Asszociáció helyett preferáljuk a tartalmazást
- a tartalmazás sokkal zártabb (fekete doboz szerű)
- de vigyázzunk a tartalmazásból keletkező körre, illetve egy dolgot többen nem tartalmazhatnak
- A tartalmazó objektum használja a tartalmazott objektumokat
- ha kiadja akkor megsértjük a zártságot, ha meg csak tartalmazza, akkor attribútum is elég lett volna
- A tartalmazott objektum ne használja a tartalmazó objektumot
- mivel a konténer már eleve függ a tartalmazott objektumtól
- A tartalmazott objektumok ne beszélgessenek egymással közvetlenül
- túl sok keresztfüggőséghez vezetne ez, inkább konténeren keresztül beszélgessenek
Öröklődés
- Az öröklődés célja mindig a viselkedés újrahasznosítása
- arra a tartalmazás és delegáció való
- Az öröklődés helyett preferáljuk a tartalmazást
- erre jó a dekorátor minta
- A közös viselkedéssel nem rendelkező közös adat, tartalmazás relációban legyen
- azaz ne a Polyline, Line és Circle rendelkezzen x, y attribútummal az ősüktől származtatva
- hanem legyen külön egy Point osztály, és abból tartalmazzanak elemeket
- A közös viselkedéssel rendelkező közös adat ősosztályban legyen
- kivétel, ha többszörös öröklődésre nincs lehetőség a nyelvben → strategy osztály használata ajánlott
- A közös viselkedés és közös adat minél magasabban legyen az öröklési hierarchiában
- azaz amilyen magasan csak lehet
- Közös interfészt csak akkor valósítsunk meg, ha a viselkedés is közös
- duck typing → ha valami úgy mozog és hápog mint egy kacsa, akkor az egy kacsa, de nem annak kéne lennie!
- Egy osztály ne függjön a saját leszármazottaitól
- Protected láthatóságot csak metódusoknál használjunk, az attribútumok mindig privátok legyenek
- Az öröklési hierarchia legyen mély, de legfeljebb hét szintű
- Absztrakt osztályok az öröklési hierarchia gyökerében legyenek
- Az öröklési hierarchia gyökerében interfészek vagy absztrakt osztályok legyenek
- Soha ne vizsgáljuk egy objektum típusát, használjunk helyette polimorfizmust
- TDA elv
- Acyclic Visitor nem szegi ezt meg, pedig lekér típust (ez valami súlyos dolog :| )
- Soha ne kódoljuk a típust enum vagy int értékekbe, használjunk helyette polimorfizmust
- Ne készítsünk függvényeket a típusok illetve a képességek megkülönböztetésére, használjunk helyettük polimorfizmust
- Ne keverjük össze a leszármazottakat az objektumokkal! Vigyázzunk azokkal a leszármazottakkal, amelyekből csak egyetlen példányt hozunk létre!
- tényleg adnak e hozzá viselkedést, vagy módosítanak e az ős viselkedésén?
- ha nagyon hasonlít egymásra a leszármazottak viselkedése, érdemes lehet új őst csinálni
- A statikus szemantikát és kényszereket a modell struktúrájába építsük be!
- ha kevés a helyes kombináció (pl pajzsos torony, repülő csapda, lövő torony van csak)
- A statikus szemantikát és kényszereket a konstruktorba építsük be!
- ha túl sok a helyes kombináció
- A dinamikus szemantikát és kényszereket viselkedésként implementáljuk
- A gyakran változó dinamikus szemantikát és kényszereket külső viselkedésként implementáljuk
- Az opcionális elemeket tartalmazásként implementáljuk, ne öröklődéssel
- hasznos lehet a nullobject minta
- Ne keverjük össze a statikus és dinamikus kényszereket
- Ha reflection-re van szükségünk, modellezzünk osztályokat, ne objektumokat
- Ha az ős működését üres implementációval írjuk felül, akkor hibás az öröklési hierarchia
- Törekedjünk újrahasznosítható API írására, ne csak újrahasznosítható osztályokéra
- Ha többszörös öröklődésre van szükségünk, gondoljuk át még egyszer a terveket
- Heterogén kollekció problémáira sokszor a Visitor minta jelent megoldást