Nade mi van, ha ezeket kirakjuk valami kozos valtozoba (DRY)?
--
public static final String BEACHBALL = "beachball";
public static final String VOLLEYBALL = "volleyball";
...
String typeValue = (String) paramValue.get("type");
if (BEACHBALL.equals(typeValue)) {
// do something
} else if (VOLLEYBALL.equals(typeValue)) {
// do something else
}
...
somewhereElseInTheCodebase();
if (BEACHBALL.equals(typeValue)) {
// do something
} else if (VOLLEYBALL.equals(typeValue)) {
// do something else
}
--
Mit nyertunk most, azon kivul, hogy megtanultunk egy uj shortcutot az IDE-ben? Hat, hogy kihasznaljuk a forditot es az IDE-t a kod validalasaban! Nem nekunk (vagy az utodunknak) kell kezzel melozni azert, hogy a kod ne omoljon ossze, hanem megoldja ezt helyette a fordito, mi meg fokuszalhatunk a koddal valo birkozas helyett az erdemi munkara. Nincs veletlen typo, hiszen valtozot hasznalunk, nem stringet. Refaktoralas, atnevezes hipi-szupi konnyu, akar a valtozonev, akar az ertek elnevezese valtozik.
Na de lehet am ezt meg cifrazni azzal, ha az egeszet kitesszuk enum-ba, aminek leginkabb csoportositasi/olvashatosagi szerepe van, nem beszelve arrol, hogy igy a kulonbozo ertekek mar osztalyokon ativeloen is hasznalhatoak (DRY).
--
public enum ParameterType {
BEACHBALL, VOLLEYBALL
}
...
String typeValue = (String) paramValue.get("type");
ParameterType type = ParameterType.valueOf(typeValue);
if (ParameterType.BEACHBALL.equals(type)) {
// do something
} else if (ParameterType.VOLLEYBALL.equals(type)) {
// do something else
}
...
somewhereElseInTheCodebase();
if (type.equals(ParameterType.BEACHBALL))) {
// do something
} else if (type.equals(ParameterType.VOLLEYBALL)) {
// do something else
}
--
Ezzel elertuk, hogy mar a kod elso olvasasa alatt is teljesen vilagos, hogy mi az a INTEGER es STRING amirol szo van (parameter tipus), utana is tudunk nezni, hogy az meg milyen ertekeket vehet fel, nem kell a kodbazist vegigbogaraszni.
En alapvetoen ugy vagyok ezzel, hogy szerintem ha nem is a kod irojanak a kotelessege ezeket kirakni _legalabb_ egy konstansba, de akkor annak, aki legkozelebb piszkalja a kod ezen reszet. Konstansba kirakni meg azert is nagyon jo, hiszen mint megallapitottuk, a refaktoralas egyszeru, ha segit a fordito, es sikit, ha nem mindenhol irtuk at a kodot pl. enumosra.
Aki akar kuldeni egy ekezetes valtozatot, ne kimeljen, kicserelem :)
Szerk: es meg akar az egeszet at is rakhatjuk egy switch-case-be, amivel megintcsak sokat nyerunk olvashatosag teren!
--
public enum ParameterType {
BEACHBALL, VOLLEYBALL
}
...
String typeValue = (String) paramValue.get("type");
ParameterType type = ParameterType.valueOf(typeValue);
switch (type) {
case BEACHBALL:
// do something
break;
case VOLLEYBALL:
// do something else
break;
}
...
somewhereElseInTheCodebase();
switch (type) {
case BEACHBALL:
// do something
break;
case VOLLEYBALL:
// do something else
break;
}
--
Edit: megvaltoztattam a parameter type-okat integer es string-rol beachball es volleyballra, mert nem volt egyertelmu paraknak, hogy ez most reflection, vagy honnan van az a type (a peldat egy JSON object feldolgozasabol vettem).
- Hevi blogja
- A hozzászóláshoz be kell jelentkezni
- 1105 megtekintés
Hozzászólások
Egy megjegyzés: ha meglátok egy INTEGER nevű konstansot, vagy kitalálom mi van benne, vagy nem. Talán jobb lenne az S_INTEGER név, ha String vagy N_INTEGER, ha szám.
Már csak azért is, hogy ne tűnjön úgy, hogy a konstans neve meg kell egyezzen a tartalmával: az utóbbi megváltozhat, amikor Tibeti nyelvre fordítjuk a programot, míg az előbbi remélhetőkeg megmarad.
- A hozzászóláshoz be kell jelentkezni
Egy megjegyzés: ha meglátok egy INTEGER nevű konstansot, vagy kitalálom mi van benne, vagy nem. Talán jobb lenne az S_INTEGER név, ha String vagy N_INTEGER, ha szám.
Ez a hungarian notation, amirol azert jo leszokni. Ez a "vagy kitalalom, mi van benne, vagy nem" annyit jelent csak, hogy rosszul van elnevezve a konstans.
- A hozzászóláshoz be kell jelentkezni
Off: Ennél egy kicsit részletesebben itt van a dolog kitárgyalva:
Joel on Software: Making Wrong Code Look Wrong
- A hozzászóláshoz be kell jelentkezni
Ez a Systems Hungarian.
A rendes hungarian notation nem erről szól. Hanem arról, hogy mondjuk van két egész számod, az egyik oszlopok számát tárolja (cntCols), a másik meg mondjuk egy indexváltozó (iCol), akkor nem igazán jó összeszorozni őket, mert az eredmény kérdéses típusú. Mi van, ha egy countert összeszorzol egy indexváltozóval? Általában nincs értelme a műveletnek, ez gyanús. Míg annak van, hogy összehasonlítod őket (ez a legtermészetesebb felhasználás).
Simonyi ötlete volt ez, a fizikából vette: az egyik oldalán egy kifejezésnek ha négyzetméterek vannak, akkor a másik oldalon nem lehet kilojoule és másodperc, nem jön ki a dimenzió.
Amúgy vannak programozási nyelvek, meg libraryk, amelyek az egyes változókra akarnak mértékegységeket is bevezetni, hogy fordítási időben kiderüljön, hogy hülyeséget akarsz leírni (például egy sorszámot összeszorozni egy hosszal).
- A hozzászóláshoz be kell jelentkezni
Mértékegység pl. F#-ban
Fuszenecker Róbert
- A hozzászóláshoz be kell jelentkezni
Ez egy tök jó dolog, nem is tudtam, hogy az F# tud ilyet. Király!
- A hozzászóláshoz be kell jelentkezni
"if (INTEGER.equals(typeValue)) {
// do something
} else if (STRING.equals(typeValue)) {
// do something else
}"
Ilyeneknek pontosan egy helyen szabad előfordulnia a kódbázisban. Abban a factoryben, ami a StringBasedImplementationt és az IntegerBasedImplementationt példányosítja.
Aztán a többi helyen már nincs if(type == ez) else if(type = az).
Pont azért van típusrendszerünk, hogy ne kelljen ilyeneket többször leírni a kódban, hanem az egyes típusimplementációkra delegálni a feladatot. És így persze több típussal kiegészíteni a kódot is csak annyiból áll, hogy a factoryt bővíted.
Ha több helyen is van if (KONSTANS == type) típusú kód, az egy nagyon rossz code smell. Nem véletlenül van (haha, mily csodás név) típusrendszere az OOP nyelveknek.
- A hozzászóláshoz be kell jelentkezni
Igy van, csak annyira nem akartam elore rohanni :)
- A hozzászóláshoz be kell jelentkezni
Bár ezt írtad, csak nem mondtad ki: erről szól az Open/Closed principle, hogy ne kelljen a használati oldalhoz hozzányúlni, ha bejön egy új típus.
- A hozzászóláshoz be kell jelentkezni
Az Open/Closed nem erről szól szerintem, hanem igazából a mechanism vs policy elkülönítésről.
A mechanism-höz nem kell hozzányúlni, ha új policyt akarsz implementálni.
Persze ez az egyik felhasználása, ahol új típus valójában új policyt jelent.
https://en.wikipedia.org/wiki/Separation_of_mechanism_and_policy
Aki persze nem Open/Closed principle szerint kódol, az nem tudja megvalósítani a mechanizmus és a policy szétválasztását.
- A hozzászóláshoz be kell jelentkezni
Ajánlott videó a témában:
https://www.youtube.com/watch?v=4F72VULWFvc
Amúgy MINDEN if, switch, ami példányosításon kívül történik, helyettesíthető polimorfizmussal.
- A hozzászóláshoz be kell jelentkezni
Edit a postban.
Masik tanulsag, a hup-os kozonseg szinvonalat alapul venni, mint baseline szakmai tapasztalatban es megertesben nem jo otlet, mert baromi sok kollega nem fogja erteni, hogy mirol is hablatyolsz :) Szoval erdemes kicsit kifejtosebben irni ilyeneket, hogy a tapasztalatlanabbaknak is atjojjon.
Illetve azon is gondolkozom, hogy lehet erdemes lesz majd 5-15 perces villambeszelgeteseket tartani ezekrol, megiscsak jobban atjohet szoban a dolog, kar hogy verbalisan (vagy ugy egyaltalan) nem tudok magyarazni :)
- A hozzászóláshoz be kell jelentkezni
Alakul ez, de mindketten tudjuk, hogy még mindig nem az igazi :)
Mikor lesz blogposzt a rendes megoldásról?
- A hozzászóláshoz be kell jelentkezni
Amire szanom, arra ez ugyan pont eleg, de abban igazad van, hogy ne vegezzunk fel munkat :) Mit raknal meg bele a fenti kommentedben emlitetten kivul?
- A hozzászóláshoz be kell jelentkezni
Magát a factoryt. Ugyanis olyan nincs, hogy a codebaseben más helyen is előfordul switch az enumra a factoryn kívül.
Hogy értsük:
van egy interface, mondjuk a példa szerint a Ball. Ennek két implementációja, a Volleyball és a Beachball.
És a két helyen, ahol használod a dolgokat, azt mondod:
String ballType = "myparam";
Ball ball = Balls.of(ballType);
ball.doThis();
// somewhere else
String ballType = "myparam2";
Ball ball = Balls.of(ballType);
ball.doThat();
Ennyi. A hívó kód (azaz a mechanizmus) nem is tudja, hogy hányféle Ball típus (azaz policy) van a rendszerben (nem is szabad tudnia), mégis tud mindegyikkel együttműködni, akárhány van.
És a Balls.of() factory methodban van egyedül switch(), sehol máshol.
Persze ehhez az kell, hogy a Ball interface szép nagy lesz, de hát a lényeg ez: MINDEN, a rendszerben előforduló típusspecifikus viselkedést tartalmazza.
Így megvalósítható az, hogy új típust úgy adj hozzá a rendszerhez, hogy biztosan tudd, mi a Ball összes viselkedése a renszerben. Lehet, hogy ez a viselkedés sokféle és a Ball interface-nek 50 metódusa lesz. Előfordul.
Szerk:
Esetleg meghivatkoznám még ezeket a dolgokat, ha már szóbakerült a polimorfizmus, és az O/C principle.
https://8thlight.com/blog/uncle-bob/2014/05/12/TheOpenClosedPrinciple.h…
https://www.youtube.com/watch?v=4F72VULWFvc
https://sourcemaking.com/refactoring/smells/switch-statements
https://sourcemaking.com/refactoring/replace-type-code-with-class
https://sourcemaking.com/refactoring/replace-type-code-with-subclasses
https://sourcemaking.com/refactoring/replace-conditional-with-polymorph…
- A hozzászóláshoz be kell jelentkezni