260 likes | 360 Views
Az objektum-orientált tervezési alapelvek kritikai vizsgálata. Kusper Gábor, EKF, MatInf Intézet Márien Szabolcs, Wit-Sys ZRt. Tartalom. Tervezési alapelvek: GOF1, GOF2, SRP, OCP Egy új elv: DLP – Decision Lifting Principle Néhány összefüggés a régi és az új elvek közt:
E N D
Az objektum-orientált tervezési alapelvek kritikai vizsgálata Kusper Gábor, EKF, MatInf Intézet Márien Szabolcs, Wit-SysZRt.
Tartalom • Tervezési alapelvek: • GOF1, GOF2, SRP, OCP • Egy új elv: DLP – Decision Lifting Principle • Néhány összefüggés a régi és az új elvek közt: • OCP ~ DLP • GOF2 ~DLP • Összefoglaló
GOF1 • „Program to an interface, notanimplementation!” • „Programozz felületre implementáció helyett!”
GOF1 megszegése 1. • importjava.util.*; • publicclassMyHashSetextendsHashSet{ • privateintaddCount = 0; • publicboolean add(Object o){ • addCount++; • returnsuper.add(o); • } • publicbooleanaddAll(Collection c){ • addCount += c.size(); • returnsuper.addAll(c); • } • publicintgetAddCount(){ returnaddCount; } • }
GOF1 megszegése 2. • importjava.util.*; • publicclass Main { • publicstaticvoid main(String[] args){ • HashSet s = newMyHashSet(); • String[] abc = {"a","b","c"}; • s.addAll(Arrays.asList(abc)); • System.out.println(s.getAddCount()); • } • }
GOF1következményei • Kerülni kell az öröklést, vagy legalább • Kerülni kell a super (C#-banbase) hívásokat. • A kliens csak a szolgáltató felületét ismerje. azaz • A szolgáltatás egy absztrakt osztály / interface mögött legyen. azaz • Minden hierarchia tetején egy absztrakt osztály legyen.
GOF2 • „Favorobjectcomposition over classinheritance!” • „Használj objektum összetételt öröklés helyett, ha csak lehet!” • Öröklés: IS-A kapcsolat, könnyen érthető • Objektum összetétel: HAS-A kapcsolat, bonyolultabb • Objektum összetétel fajtái: • Aggregáció: Ha meghal a gitáros, nem temetik vele a gitárját. • Kompozició: Ha meghal a gitáros, vele temetik a gitárját.
Az öröklődés mindig kiváltható objektum összetétellel
GOF2 következményei • Öröklést kerülni kell. • Rugalmasabb, de nehezebben érthető lesz a kód. • Lehetőséget add arra, hogy futási időben injektáljunk be felelőséget. • A GOF2-nek ismerjük az előnyeit és hátrányait, de nem tudjuk, mikor kell használni!!!
SRP - SingleResponsibilityPrinciple • „A classshouldhaveonlyonereasontochange” • „Az osztályoknak csak egy oka legyen a változásra” • Programozás technológia elve: • „A program kódja állandóan változik” • Az SRP azt mondja ki, hogy egy változás hatására csak egy osztály változzon meg.
SRP következményei • Kerüljük a MacsKuty típusú osztályokat: • Akkor is megváltozik, ha kiderül, hogy a Kutya nem csak ugatni tud, • És akkor is megváltozik, ha kiderül, hogy a Macska nem csak egerészni tud. • Sok-sok unit teszt alkalmazása: • TDD – Test DrivenDevelpment • Használjuk Aspektus-Orientált Programozást • pl. logolásra, jogosultság ellenőrzésre
Egy összefüggés: SRP ~ GOF1 • A GOF1 megszegése gyakran az SRP megszegéséből ered: • Ha egy osztály nem teljesen fedi le a fellelőség köreit, akkor egy másik osztálynak kell megvalósítani ezeket. Ehhez viszont ismernie kell az eredeti osztály megvalósítását, tehát megszegjük a GOF1-et.
OCP - Open-ClosedPrinciple • „Classes should be open for extension, but closed for modification” • „Az osztályok legyen nyitottak a bővítésre, de zártak a módosításra” azaz • „Az osztály hierarchia legyen nyitott a bővítésre, de zárt a módosításra”
OCP megszegésére utaló jelek • Bonyolult if – elseif vagy switch szerkezetek. • Override használata. • Csak absztrakt és hook metódusok felülírását engedi.
OCP megszegése • class Alakzat { • publicconst int TEGLALAP = 1; publicconst int KOR = 2; int tipus; • public Alakzat(int tipus) { this.tipus = tipus; } • public int GetTipus() { returntipus; } • } • classTeglalap : Alakzat{Teglalap():base(Alakzat.TEGLALAP){}} • class Kor : Alakzat{ Kor():base(Alakzat.KOR){} } • classGrafikusSzerkeszto { • publicvoidRajzolAlakzat(Alakzat a) { • if (a.GetTipus() == Alakzat.TEGLALAP) RajzolTeglalap(a); • elseif (a.GetTipus() == Alakzat.KOR)RajzolKor(a); • } • publicvoidRajzolKor(Kor k) { /* … */ } • publicvoidRajzolTeglalap(Teglalap t) { /* … */ } • }
DLP - Decision Lifting Principle • „Öröklést csak döntés kiemelésre használj!” • „Useinheritanceonlyfordecision lifting!” • DLP megszegésére utaló jelek: • Ismétlődő if – elseif szerkezetek. • Ismétlődő switch szerkezetek.
DLP megszegése • class Alakzat { • publicconst int TEGLALAP = 1; publicconst int KOR = 2; int tipus; • public Alakzat(int tipus) { this.tipus = tipus; } • public int GetTipus() { returntipus; } • } • classTeglalap : Alakzat{Teglalap():base(Alakzat.TEGLALAP){}} • class Kor : Alakzat{ Kor():base(Alakzat.KOR){} } • classGrafikusSzerkeszto{ • publicvoidRajzolAlakzat(Alakzat a) { • if (a.GetTipus() == Alakzat.TEGLALAP) RajzolTeglalap(a); • elseif (a.GetTipus() == Alakzat.KOR)RajzolKor(a); • } • publicvoidRajzolKor(Kor k) { /* … */ } • publicvoidRajzolTeglalap(Teglalap t) { /* … */ } • }
DLP betartása • abstractclass Alakzat{ publicabstractvoid Rajzol(); } • classTeglalap : Alakzat { • publicoverridevoid Rajzol() { /* téglalapot rajzol */ } • } • class Kor : Alakzat { • publicoverridevoid Rajzol() { /*kört rajzol */ } • } • classGrafikusSzerkeszto{ • publicvoidRajzolAlakzat(Alakzat a) { a.Rajzol(); } • } • class Program { • publicstaticvoid Main(String[] args) { • Alakzat alak = new Kor(); • (newGrafikusSzerkeszto()).RajzolAlakzat(alakzat); • }}
Összefüggés az OCP és a DLP közt • Az OCP azt mondja, hogy kerüljük a bonyolult if – elseif szerkezeteket. • A DLP azt mondja, hogy kerüljük az ismétlődő if – elseif szerkezeteket. Ugyanakkor meg is mondja, hogyan szüntessük meg az ismétlődést: • Döntéskiemelésselű • A bonyolult if – elseif szerkezetek is döntéskiemeléssé degradálhatok egyszerű példányosítássá.
Összefüggés a GOF2 és a DLP közt • GOF2: „Használj objektum összetételt öröklés helyett, ha csak lehet!” azaz • Hacsak lehet ne használj öröklést! • DLP: „Öröklést csak döntés kiemelésre használj!” • A DLP pontosítja a GOF2-t, hiszen megmondja, mikor kell öröklést használni, egyébként pedig objektum összetételt kell használni.
Összefoglalás • Nagyon sok tervezési alapelv van. • Van amelynél tudható, hogy milyen esetben hogyan kell átalakítani a programot: GOF1, OCP, DLP. • Van amelynél nem tudható, hogy kell-e használni a konkrét esetben, habár sok elméleti előnnyel jár: GOF2, SRP. • Bevezettünk egy új tervezési alapelvet, a DLP-t, amely megmondja mely esetekben nem használandó a GOF2.
Köszönöm a figyelmet! Email címek: Kusper Gábor: gkusper@aries.ektf.hu Márien Szabolcs: szabolcs.marien@wit-sys.hu
Néhány összefüggés • Ha úgy sértjük meg az SRP-t, hogy egy osztály nem teljesen fedi le a fellelőség köreit, akkor egy másik osztálynak kell megvalósítani ezeket. Ehhez viszont ismernie kell az eredeti osztály megvalósítását, tehát megszegjük a GOF1-et. • Ha úgy sértjük meg az SRP-t, hogy egy osztály több felelőségi kört is lefed, akkor megszegjük a GOF2-öt, mert a két felelőséget szét lehetne szedni két osztályra, amit egy harmadik foghatna össze objektum összetétellel.