Egy kis OOP elmélet
2009.05.13. 12:59
Kaptam egy mérsékelten humoros spam-et, amiben közmondások (vagy szólások? ebben sosem voltam jó) vannak kódként megfogalmazva. Önmagában nem ér meg egy bejegyzést, de úgy gondoltam, hogy alkalmas arra, hogy felhívjam a figyelmet néhány tipikus OOP tervezési hibára. Még mielőtt lehülyézne valaki, szólok, hogy értem én, hogy ez vicc, csak lesz*rom.
A leírt elképzelések nagyon elméletiek. A gyakorlatban legtöbbször nem tudjuk alkalmazni a szép tervezésre vonatkozó szabályokat, emiatt ezek igazából csak filozófálgatásra jó meglátások. Nos, lássuk a levél tartalmát:
// Ki korán kel, aranyat lel
if (userLoggedIn.getWakeUpTime() < strToTime("06:00:00"))
userLoggedIn.foundItems.add(GOLD);
// Egyszer volt Budán kutyavásár
const int NUM_DOG_EXPO_IN_BUDA = 1;
// Ki mint vet, úgy arat
aratas.setQuality(vetes.getQuality());
// Ajándék lónak ne nézd a fogát
if (horse.getOrigin() == SOUVENIR)
horse.teeth.canLookAt = false;
// A hazug embert hamarabb utolérik mint a sánta kutyát
bool doesTruthExist()
{
return liar.getCaptureTime() < crippleDog.getCaptureTime();
}
// Kerülgeti mint macska a forró kását
agent.sideStep(cat.getWalkType(new Kasa(HOT)));
// Aki másnak vermet ás, maga esik bele
stack.push(stack.madeBy());
// A napra lehet nézni, de rá nem
sun.canLookAt = true;
she.canLookAt = false;
// Madarat tolláról, embert barátjáról
bird.setType(bird.getFeather().getType());
human.setType(human.getFriend().getType());
// Éhes disznó makkal álmodik
if (pig.getType() == HUNGRY)
pig.startDreamAbout(MAKK);
// Nem a győzelem, a részvétel a fontos
winning.setPriority(LOW);
attendance.getPriority(HIGH);
// A szomszéd fűje mindíg zöldebb
bool Grass::compareGreenness(const Grass& other) const
{
return other.getOwner() == NEIGHBOUR;
}
// Lassan járj, tovább érsz
passedDistance += 42.0 / WalkSpeed;
// Okos enged, szamár szenved
if (human.getType() == SMART)
human.Release();
else if (human.getType() == DONKEY)
human.Suffer();
Első példának nézzük ezt:
// Ajándék lónak ne nézd a fogát
if (horse.getOrigin() == SOUVENIR)
horse.teeth.canLookAt = false;
Ez tipikus példája a felelősségi körök összekutyulásának. A ló foga nem tudhatja, hogy rá lehet-e nézni vagy sem. Persze bizonyos helyzetekben helyes lehet az ilyen kódszervezés, de semmiképpen nem olyan fogalmakkal, mint ló, fog és ránézni. Ez a kódrészlet helyesen így festene:
if (horse.getOrigin() == SOUVENIR)
{
actor.registerCanLookat(horse.teeth, false);
}
Az aktor tulajdonsága az, hogy ránézhet-e a lóra, és a ránézés is az ő metódusa lesz (mondjuk: actor.LookAt(horse);)
Következő példa:
// A hazug embert hamarabb utolérik mint a sánta kutyát
bool doesTruthExist()
{
return liar.getCaptureTime() < crippleDog.getCaptureTime();
}
Ha eltekintünk a vicctől, ez teljesen értelmetlen. Igazából ez nem tervezési hiba, hanem rossz specifikáció. Az, hogy egy esemény mennyi ideig tart (capturetime) nem lehet egy osztály tulajdonsága, hanem inkább egy mérés eredménye, ami független az osztálytól. Ezt jóra átírni nem tudom, mert a specifikáció (a komment) egy állítás, és egy mért eredménnyel (kell lennie) nem lehet egy állítást ütköztetni (ilyen probléma amúgy később is előfordul a szomszéddal meg a fűjével kapcsolatban). A kód akkor lenne jó, ha a komment kérdés lenne, és akkor is így festene:
// A hazug embert hamarabb utolérik mint a sánta kutyát?
bool doesTruthExist()
{
captureData liarCaptureData = actor.Capture(liar);
captureData crippledogCaptureData = actor.Capture(crippledog);
return liarCaptureData.CaptureTime < crippledogCaptureData.CaptureTime;
}
Persze a túlbonyolított vicc sose jó. Menjünk tovább. Itt ugyanaz a probléma, mint a ló esetében:
// A napra lehet nézni, de rá nem
sun.canLookAt = true;
she.canLookAt = false;
Sem a nap, sem a csaj nem tudhatja magáról, hogy egy másik entitás rá tud-e nézni. Persze más megfogalmazásban ez is jó lehet, de ezekkel a fogalmakkal semmiképpen sem.
És utoljára:
// Lassan járj, tovább érsz
passedDistance += 42.0 / WalkSpeed;
Ez azt jelenti, hogy csak 42-t mehetünk. De miért pont 42? Mert az a válasz univerzum, meg a világmindenség legnagyobb kérdésére? Vagy maratont járunk? Nekem így jobban néz ki:
passedDistance += (1 / WalkSpeed) * time;
Persze ez csak vicc. Ja. Muhaha.
A bejegyzés trackback címe:
Kommentek:
A hozzászólások a vonatkozó jogszabályok értelmében felhasználói tartalomnak minősülnek, értük a szolgáltatás technikai üzemeltetője semmilyen felelősséget nem vállal, azokat nem ellenőrzi. Kifogás esetén forduljon a blog szerkesztőjéhez. Részletek a Felhasználási feltételekben és az adatvédelmi tájékoztatóban.