Vissza az előzőleg látogatott oldalra (nem elérhető funkció)Vissza a tananyag kezdőlapjára (P)Ugrás a tananyag előző oldalára (E)Ugrás a tananyag következő oldalára (nem elérhető funkció)Fogalom megjelenítés (nem elérhető funkció)Fogalmak listája (nem elérhető funkció)Oldal nyomtatása (nem elérhető funkció)Oldaltérkép megtekintése (D)Keresés az oldalon (nem elérhető funkció)Súgó megtekintése (S)

Modern programozási minták a kliens és szerveroldali webprogramozásban / Modern programozási minták a szerveroldalon PHP-ban

Tanulási útmutató

Összefoglalás

A tananyag zárásaként kitekintést adunk a korszerű szerveroldali programozási mintákra a PHP nyelvben.

Programozási minták PHP-ban

A modern szoftverfejlesztés sarokköve a karbantarthatóság lett. Ma már nem számít a számítási kapacitás, nem kell lépten-nyomon optimalizációval foglalkozni — elég azokban a ritka esetekben, ha valódi problémát okoz vagy okozhat. Amíg 30-40 évvel ezelőtt a fejlesztők legnagyobb gondja az volt, hogy hogyan fognak nagyobb adatmennyiséget vagy egy bonyolultabb algoritmust elvégezni a végtelenül limitált memória, processzoridő és háttértár mellett, addig ez már szerencsére nem sújtja a mai fejlesztők nagy részét.

A közelmúlt szoftverkrízise

A klasszikus fejlesztési modellben próbálták minimálisra szorítani a szoftver komplexitását, mert nem voltak meg azok a módszerek, amellyel hatékonyan lehetett volna óriási szoftvereket menedzselni. Amikor 15-20 évvel ezelőtt végre fellélegezhettek a fejlesztők, az erőforrás-kezelés helyett a szoftverfejlesztés más területeire összpontosíthattak, akkor megjelentek a komplex, óriási funkcionalitást megvalósító szoftverek. Amikor az üzleti igényeket előtérbe helyezve, emberi erőforrásokat nem kímélve egyre csak duzzasztották a kódbázisaikat, akkor teljes sebességgel rohantak egy újabb zsákutca felé. A legtöbb monolitikus szoftver életében eljön az a pont, amikor már nem elég újabb és újabb fejlesztőt a projekt mögé állítani — egyszerűen egyik napról a másikra összedől.

Ezen a ponton sok szoftverfejlesztő vállalat kényszerült stratégiájának újragondolására — most már óvatosabban, de szép lassan elmozdultak egy agilisabb irányba. Bár utóbbi alatt legtöbbször az ügyfélközpontú, nem túltervezett, inkrementális fejlesztést értjük, azonban fontos hozadéka a minőségi és karbantartható szoftver előállítása is.

Vissza a tartalomjegyzékhez

Problémák az öröklődéssel

A goto vezérelte kódok legnagyobb problémája az átláthatatlanság és a kiszámíthatatlanság volt. A leváltására óriási igyekezettel vetették bele magukat a fejlesztők a procedurális kódba, amely már megfelelő struktúrát biztosíthatott a szoftvernek. Egy bizonyos ponton túl azonban menedzselhetetlenné váltak a függőségek és az állapotváltozók, a kódbázisok a láthatóság korlátozását kívánták meg.

Az objektum-orientált programozás megjelenésével sikerült egységbe zárni az alkalmazás különböző részeit, elrejtve egymás elől a saját, privát állapotterüket. Az újonnan megjelenő program-egységek, az osztályok körében már megjelent az öröklődés is, amely hatékony eszköz volt a kódduplikálás felszámolására. Minden megismételt kód nehezíti a karbantarthatóságot, hiszen ha módosítanánk a viselkedésén, akkor azt minden duplikátum esetében meg kellene tenni. Jó ötletnek tűnt a hasonló osztályok közös metódusait egy ősosztályba kiemelni és ebből származtatni őket.

Természetesen — mint ahogy a fejlesztési minták nagy részét — az öröklődést is határok nélkül kezdték el használni a fejlesztők és legtöbbször rosszul. A közös függvény fogalma teljesen helyzetfüggő és sokszor egy metódus — amit az egyik pillanatban jó ötletnek tűnt egy ősbe kiemelni — egy másik gyerek-osztályban értelmetlenné válik. Erre a problémára nyújt megoldást a Kompozíció az öröklődés felett elve.

Kompozíció az öröklődés felett

A túlbonyolított objektum-orientált szerkezet gyakori probléma és jelenléte teljesen érthető. A legtöbb szakirodalom az öröklődést nevezi meg a duplikátumok megszüntetésének elsődleges eszközeként. Kis felelősségű osztályok esetén még működik is az elv, azonban, ahogy nő a programegység úgy veszíti el az öröklődés is az értelmét. Az örökölt metódusok egyre nagyobb galibát okoznak, amíg végül — szerencsés esetben — valaki ki nem refaktorálja. Amikor egy metódust egy ősosztályhoz rendelünk akkor valójában egy viselkedést láncolunk az összes belőle származó példányhoz és gyerek-osztály-példányhoz. Nem tudunk csak úgy egy nem kívánt viselkedést eltüntetni a gyerek-osztályból.

Nézzünk a problémára egy egyszerű példát: tegyük fel, hogy egy hősökkel teli játékprogramot írnánk, ahol szereplőink a támadhatnak, védekezhetnek és hasonló tipikus hős-képességgel rendelkeznek. Természetesnek tűnik, hogy közös képességeiket emeljük ki egy közös ősosztályba, ami valahogy így nézne ki:

Forráskód
abstract class Hero {
    public function attack() {
        echo "Smash the enemy with a sword!";
    }
    public function defend() { ... }
    public function getHealth() { ... }
}

A Hero őst definiáljuk absztrakként, hiszen közvetlenül nem szeretnénk példányosítani. Hozzunk létre pár hőstípust, amelyek pont a hősök tipikus viselkedését valósítják meg, így az őstől örökölt tulajdonságok semmilyen nemű módosítására nincs szükség részükről:

Forráskód
class Warrior extends Hero 
class Viking extends Hero 
$erik = new Viking();
$erik->attack(); // => "Smash the enemy with a sword!";

A harcos és a hős definiálása így egyszerű volt. Nézzünk egy nüansznyival bonyolultabbat. Tegyük fel, hogy egy varázslóra is szükség van, ő viszont nyilván nem karddal támad az ellenségre. Sebaj, az öröklődésnek hála a gyerek-osztályban könnyedén felüldefiniálhatjuk az attack viselkedését:

Forráskód
class Mage extends Hero {
    public function attack() {
        echo "Cast a spell on the enemy!";
    }
    public function shave() 
}

Mágusunk a barbár harcostól és vikingtől eltérően már kellőképpen képzett a borotválkozás témájában is, így ő ezzel a sajátságos függvénnyel is rendelkezik. Semmi probléma, egyelőre szép objektum-orientált kódunk van.

A játékostársadalom hirtelen elégedetlen lesz a játékbeli nemek arányával, így kénytelenek vagyunk implementálni a boszorkány karaktert is. A boszorkány a mágushoz hasonlóan inkább a varázslásban jártas, mint a kardvívásban. Jelen pillanatban nem igazán tudunk mást tenni, mint azt, hogy az attack metódust lemásoljuk új hősünk implementációjába is, ezzel nem kívánt kód-duplikációt okozva:

Forráskód
class Witch extends Hero {
    public function attack() {
        echo "Cast a spell on the enemy!";
    }
}

Bár adná magát a megoldás, hogy származtassunk a Mage osztályból, azonban annak shave metódusa miatt összeférhetetlen a boszorkánnyal.

Egy másik lehetőség lenne új közös ősbe kiemelni az attack metódust és mindkettő osztály illetve a Hero közé ékelni a köztes-osztályt. Ez ideig-óráig működhet is, azonban, hogyha egy másik tulajdonságban is hasonlítanak (pl. varázserő lekérdezés), de egy harmadikban nem (pl. a boszorkány el tud valakit csábítani), akkor olyan probléma áll elő, amit az öröklődés már nem tud megoldani.

A fentiek más gondot is okoznak: nagyon hamar túlbonyolítjuk, követhetetlenné tesszük az osztályhierarchiánkat. Ahogy vertikálisan nő a hierarchia, úgy kötjük meg egyre inkább a gyerek-osztályokat és úgy tudjuk egyre kevésbé átlátni, hogy egy gyerek pontosan milyen tulajdonságokkal is rendelkezik.

A megoldást a kompozíció jelenti, vagyis az, hogy a tulajdonságokat vegyük ki egy külön osztályba és ezt a viselkedés-osztályt injektáljuk az ősosztályba. Ekkor az adott gyerek-osztály jellemzőit azáltal szabályozhatjuk, hogy milyen tulajdonságot példányosítunk benne.

Először is készítsük el a viselkedés-osztályainkat:

Forráskód
interface AttackAbility {
    public function attack();
}
class SwordAttack implements AttackAbility {
    public function attack() {
        echo "Smash the enemy with a sword!";
    }
}
class SpellAttack implements AttackAbility {
    public function attack() {
        echo "Cast a spell on the enemy!";
    }
}

Módosítsuk az ősosztályt úgy, hogy mostantól a képesség-osztályokat használja:

Forráskód
abstract class Hero {
    /** @var AttackAbility */
    protected $attackAbility;
    function __construct($attackAbility = null) {
        $this->attackAbility =
            $attackAbility ? $attackAbility : new SwordAttack();
    }
    public function attack() {
        $this->attackAbility->attack();
    }
}

Mi is történt? A konstruktorban mostantól átadható egy viselkedés-osztály, melynek hiányában automatikusan a karddal támadás képességét kapja az osztály. A Hero attack metódusa mostantól csak egy Facade, vagyis egy egyszerűsítő felület a képesség támadás metódusára.

Mostantól nem szükséges az attack metódust felüldefiniálni a gyerek-osztályokba, elég, ha a megfelelő tulajdonságot beállítjuk a konstruktorban:

Forráskód
class Mage extends Hero {
    function __construct() {
        parent::__construct(new SpellAttack());
    }
}
class Witch extends Hero {
    function __construct() {
        parent::__construct(new SpellAttack());
    }
}
$tim = new Mage();
$tim->attack(); // => "Cast a spell on the enemy!"

A kompozíció egy másik nagyszerű lehetőséggel is bővíti az eszközkészletünk, kis módosítással futási időben ki tudjuk cserélni egy objektumpéldány viselkedését:

Forráskód
abstract class Hero {
    /** @var AttackAbility */
    private $attackAbility;
    function __construct($attackAbility = null) {
        $this->setAttackAbility($attackAbility);
    }
    public function attack() {
        $this->attackAbility->attack();
    }
    public function setAttackAbility($attackAbility) {
        $this->attackAbility =
            $attackAbility ? $attackAbility : new SwordAttack();
    }
}
$tim = new Mage();
$tim->attack(); // => "Cast a spell on the enemy!"
$tim->setAttackAbility(new SwordAttack());
$time->attack(); // => "Smash the enemy with a sword!";

Az öröklődés helyett a kompozíció használatával egy sokkal rugalmasabb kódot értünk el, ráadásul felszámoltuk a viselkedés-összeférhetetlenségek problémáját. A fenti példában használt metodikát a Stratégia tervezési mintának nevezzük és a legtöbb programozási minta alapját képezi.

Az 5.4-es PHP-ban megjelent Trait-ek segítségével sokkal könnyebben valósíthatjuk meg a viselkedések osztályokba illesztését. Egy ilyen segédosztályban metódusokat definiálhatunk amelyek bemásolódnak abba az osztályba, amihez hozzárendeljük a Trait-et. A módszer hátránya, hogy elvesztjük a futás közbeni, dinamikus viselkedés-csere lehetőségét, illetve, hogy a Trait-ben nem vagyunk képesek elszeparált, komplexebb üzleti logika megvalósítására. Utóbbi probléma oka az, hogy a Trait-ben szereplő metódusok egyszerűen bemásolódnak a cél-osztályba, de maga a segédosztály sosem példányosodik.

Vissza a tartalomjegyzékhez

Egyéb problémák az objektum-orientált világban

Az OOP rengeteg problémára adott megoldást, de mint minden módszertan, az objektum-orientált világ is hozott néhány újat.

Az igény a jól megkomponált kódra rengeteg új technikát és módszertant (pl. programtervezési minták használatát) és egy új foglalkozást, a kód-architektek megjelenését jelentette. Utóbbiak jól jöttek, mikor egy komplexebb rendszert kellett átlátni és megtervezni, azonban a saját munkájukat túlságosan komolyan vevő rendszertervezők a legkisebb feladatot is olyan mértékben el tudják bonyolítani, túl tudják tervezni, hogy az jelentősen hátráltatja a szoftver menedzselhetőségét.

A másik lényeges probléma, amivel máig szembe kell néznie minden OOP-t követő fejlesztőnek az egymáshoz túlságosan szorosan kötött programegységek. Ez rengeteg galibát tud okozni: kezdve azzal, hogy az osztályok egymástól való függése megnehezíti a refaktorálást és a tesztek írását, egészen addig, hogy egy mélyen lévő probléma a szoros egymásra utaltság miatt indokolatlanul végiggyűrűzhet az egész alkalmazáson. Egy ideális világban a szoftver — maximum néhány száz soros — mikro-szolgáltatásokra van bontva, amelyek egymással csak adatkommunikáció szintjén tartják a kapcsolatot, azonban nem függenek egymás metódusaitól, állapotától.

A fenti problémák kiküszöbölésére Michael Feathers és Robert C. Martin megfogalmazta a SOLID elveket, melyek követésével hatékonyan korlátozható az OOP, így kordában tartva az elburjánzó, kezelhetetlen kódbázisokat. A SOLID egy rövidítés, melynek minden betűje egy követendő elvet jelöl.

Single Responsibility Principle

Ez az alapelv azt mondja ki, hogy minden programrésznek (legyen az egy modul, egy osztály vagy például csupán egy metódus) egy és csak egyetlen egy okból változhat meg.

Az elv megfogalmazása kicsit trükkös, azonban nem kell túlgondolni. Egész pontosan ezt jelenti, hogy nem kell túlgondolni pl. egy osztály szerepét. Minden programrésznél tegyük fel magunknak a kérdést: „vajon ez mivel foglalkozik”? Ha egyetlen rövid mondatban tudunk erre válaszolni és a válaszban nincs benne az és vagy a vagy, akkor elértük a célunk. Az alapelv célja az, hogy minden programrész egyetlen felelősséggel rendelkezzen, csak egyetlen feladattal foglalkozzon, azonban azt maradéktalanul végezze el. Csak abban az egy esetben módosítsuk a programrész viselkedését, ha az a feladat kivitelezésével kapcsolatos!

Nézzünk egy rövid példát az SRP-re. Térjünk vissza hőseinkhez, ámde most egy kicsit más aspektusból:

Forráskód
class Hero {
    private $name;
    public function __construct($name) {
        $this->name = $name;
    }
    public function displayName() {
        echo "My name is " . $this->getName();
    }
    private function getName() {
        return $this->name . " the Hero";
    }
}
$erik = new Hero('Erik');
$erik->displayName(); // => "My name is Erik the Hero"

Ha megnézzük a fenti kódot, akkor láthatjuk, hogy egy hős példány egyszerre több felelősséggel is rendelkezik: egyrészt kezeli a saját adatait, másrészt egy tőle teljesen független dolgot is el tud végezni, ki tudja írni a nevét a képernyőre. Jelen esetben az osztálynak két oka is lehet a módosításra: ha pl. megváltozik a név generálásának módja és ha pl. nem a képernyőre vagy nem ilyen formában szeretném kiírni a hős nevét.

A probléma feloldására a legjobb megoldás, ha a display metódust kiemelnénk egy külön osztályba:

Forráskód
interface Display {
    public function show();
}
class HeroDisplayer implements Display {
    public function show(Hero $hero)
    {
        echo "My name is " . $hero->name;
    }
}
class Hero {
    private $name;
    public function __construct($name) {
        $this->name = $name;
    }
    public function getName() {
        return $this->name . " the Hero";
    }
}
$erik = new Hero('Erik');
$displayer = new HeroDisplayer();
$displayer->show($erik); // => "My name is Erik the Hero"

Most már megfelelően eloszlanak a felelősségi körök, minden osztály a neki szánt feladatot végzi el. Természetesen a HeroDisplayer beinjektálható a hős osztályába, igaz ezzel egy közvetlen függőséget felállítunk a két osztály között, azonban a két feladat üzleti logikája el van egymástól szeparálva:

Forráskód
class Hero {
    private $name;
    /** @var HeroDisplayer */
    private $displayer;
    public function __construct($name, $displayer = null) {
        $this->name = $name;
        $this->displayer = $displayer;
    }
    public function getName() {
        return $this->name . " the Hero";
    }
    public function displayName() {
        if ($this->displayer) {
            $this->displayer->show($this);
        }
    }
}
$erik = new Hero('Erik', new HeroDisplayer());
$erik->displayName($erik); // => "My name is Erik the Hero"

Open/Closed Principle

Az OCP alapelve szerint minden osztály legyen nyitott a kiterjesztésre, azonban zárt a módosításra. Az, hogy ez mit jelent tökéletesen illusztrálja a kompozíció az örökölődés felett mintája. Ha visszaemlékszünk az ottani példa konklúziójára akkor láthatjuk, hogy miről is van szó: a hős osztályok egyes viselkedései kiemelhetőek külön osztályokba és fordítási vagy futási időben kicserélhetőek.

Az OCP alapelv azt a rugalmasságot követeli meg az osztályainktól, hogy azok működése bővíthető legyen úgy, hogy közben a kódjukhoz nem nyúlunk.

Liskov Substitution Principle

Egy matematikusról elnevezett alapelv megfogalmazása természetesen precíz, mindazonáltal bonyolult kell, hogy legyen. Nem is csalódunk, ugyanis a következőképp hangzik: „Ha S altípusa T-nek, akkor minden olyan helyen ahol T-t felhasználjuk S-t is minden gond nélkül behelyettesíthetjük anélkül, hogy a programrész tulajdonságai megváltoznának.”

Hogy ez mit is jelent? Azt, hogy bárhol is használunk egy ősosztályt — legyen az egy változó, paraméter, stb. — a tőle származó osztályokat be kell, hogy tudjuk helyettesíteni ugyanide, úgy, hogy minden viselkedése hasonló maradjon.

Az alapelv szemléltetéséhez vegyünk elő egy klasszikus példát, amely tökéletes alapanyag az LSP megértéséhez:

Forráskód
class Rectangle {
    private $topLeft;
    private $width;
    private $height;
    public function setHeight($height) {
        $this->height = $height;
    }
    public function getHeight() {
        return $this->height;
    }
    public function setWidth($width) {
        $this->width = $width;
    }
    public function getWidth() {
        return $this->width;
    }
}

Adott egy négyszög, melynek beállíthatjuk a magasságát és szélességét, és egyszerűen le is kérdezhetjük ezeket az adatokat. Eddig nincs is semmi gond, ez egy egyszerű adatobjektum. Tegyük fel, hogy kiadjuk a szoftverünket és többen elkezdik használni — majd egyszer csak egy új igény érkezik az ügyfeleinktől: mostantól négyzetekkel is foglalkozni kell!

Nem esünk kétségbe, hiszen tudjuk, hogy ez egyszerű lesz, végtére is a négyzet is csak egy négyszög. Nincs is más hátra, mint, hogy implementáljuk:

Forráskód
class Square extends Rectangle {
    public function setHeight($value) {
        $this->setSize($value);
    }
    public function setWidth($value) {
        $this->setSize($value);
    }
    private function setSize($value) {
        $this->width = $value;
        $this->height = $value;
    }
}

Kénytelenek vagyunk a szélesség és a magasság beállítását is beállítani, hiszen az ősosztály már rákényszerít minket arra, hogy mindkét méretező-metódust definiáljuk. Mi ezzel a probléma? Nézzük meg egy, a négyzet előtt a szoftverbe került alkalmazás helyét:

Forráskód
class RectangleDisplayer {
    public function showLeftBorder(Rectangle $rectangle) {
        $rectangle->setWidth(2);
        $rectangle->setHeight(50);
        $this->display($rectangle);
    }
}

Mivel a Square a négyszög osztályból származik, így minden további nélkül átadható a showLeftBorder metódusnak, és ebben az esetben biztosan nem az fog történni, amit várnánk, az eredmény meglepetést fog okozni.

A négyzetnek egész egyszerűen nincs szüksége a szélesség és magasság beállítására, neki csak egy setSize metódussal kellene rendelkeznie. Bár a valóságban a négyzet valóban négyszög — ahogy a példa is mutatja — a programfejlesztésben nem feltétlenül tudjuk ugyanezeket az analógiákat követni.

A legegyszerűbb megoldás a problémára, ha e két alakzat nincs alá-fölérendelt viszonyban, de pl. mindketten származhatnak egy közös Shape osztályból.

Interface Segregation Principle

Az interfészek nagyszerű eszközök arra, hogy pl. egy paraméterlistában osztályok helyett csak adatok vagy viselkedések egy csoportját várjuk. Ez az alapelv azt mondja ki, hogy óriási, egybefüggő interfészek helyett kicsi, a feladatok alapján jól elválasztott, egyetlen dologért felelős interfészeket használjunk.

Vegyünk egy egyszerű adatnyilvántartó programot, amellyel E-mailt küldhetünk a nyilvántartott személyeknek. Ebben az esetben bizonyára létezik a személyt leíró interfész:

Forráskód
interface User {
    public function getId();
    public function getName();
    public function getAge();
    public function getAddress();
    public function getEmail();
    public function getPhone();
    public function getMothersMaidenName();
}

Tegyük fel, hogy vannak olyan felhasználói osztályok, melyek ezt az interfészt implementálják, és ennek megfelelően van egy kód, amellyel a hasonló tulajdonságúaknak levelet küldhetünk:

Forráskód
class EmailSender {
    public function sendEmail(User $user, $message) {
        ...
    }
}

Eddig minden a legnagyobb rendben is van, azonban, ha jön egy kérés, miszerint, mostantól különböző közösségek is szerepelnek a nyilvántartásban, és nekik is küldjünk E-mailt, mindjárt gondban leszünk. Implementáljuk a User interfész alapján a csoportot, hiszen a legtöbb tulajdonság illik rá:

Forráskód
class Community implements User {
    public function getId() { ... };
    public function getName() { ... };
    public function getAge() { ... };
    public function getAddress() { ... };
    public function getEmail() { ... };
    public function getPhone() { ... };
    public function getMothersMaidenName() {
        throw new WhatIsThisException();
    };
}

Itt az első bökkenő, a közösségre minden adat illik, kivéve az édesanya leánykori nevét, ami egy csoportnál értelmezhetetlen. Beleestünk a túlságosan vastag interfész hibájába — ami sokszor oda vezethet, hogy rengeteg metódust hagyunk árván, csak mert az adott osztálynak azokra nincs szüksége. Ez egy hibás tervezés eredménye, amit érdemes minél hamarabb orvosolni.

A másik probléma, hogy bár a Community-nak is küldhetünk leveleket, azonban maga az E-mailküldő metódus paraméterlistája túlságosan szűk — a sendMail metódusnak valójában csak egy getEmail-el rendelkező objektum kell.

Sokkal jobban járunk, ha az interfészeket viselkedések alapján hozzuk létre, és pl. létezne egy lényegesen kevesebb megszorítást tartalmazó interfész a kapcsolatfelvételre:

Forráskód
interface Contactable {
    public function getEmail() { ... };
    public function getPhone() { ... };
}
class Community implements User, Contactable { ... }
class EmailSender {
    public function sendEmail(Contactable $user, $message) {
        ...
    }
}

Ebben az esetben a levélküldő metódus már sokkal több osztályt fogadhat, hiszen valószínűbb, hogy több Contactable interfésszel rendelkező osztály van, mint olyan, ami a teljes User-t implementálja.

Dependency Inversion Principle

A DIP a szoftvermodulok mobilitására vonatkozó alapelv, nem összekeverendő a dependency injection-nel, bár azért lazán, de kapcsolódik az utóbbihoz. Az elv megfogalmazása a következő: - A magasabb szinten lévő programegységek nem függhetnek az alacsonyabb szintűektől, ehelyett mindkettőnek az absztrakciótól kell függenie. - Az absztrakció nem függ a részletektől, a részletek függnek az absztrakciótól.

A DIP leggyakrabban és legkönnyebben az olyan problémás kódokon látható, ahol SQL és PHP utasítások keverednek a HTML keret generálásával. Gyakran az is előfordul, hogy konkrétan az SQL utasításból jövő fejléc jelenik meg a HTML-ben, a $_GET vagy $_POST közvetlenül a HTML-be íródik és így tovább. Még olyan is előfordulhat, hogy adatbázisban tárolt PHP kódot kérünk le és futtatunk egy alapvetően HTML oldalon. Ez mind a DIP megsértése, hiszen folyamatosan kavarognak a különböző absztrakciós szintek.

Nem szabad megengedni, hogy az alkalmazás megvalósításának részletei beleavatkozzanak az alapkoncepcióba. Kitűnő példa erre egy rosszul megírt keretrendszer: tegyük fel, hogy az alkalmazásunk több különböző adatbázist is használhat, melyek között itt-ott vannak különbségek. Nyilván alapesetben úgy adódna, hogy a problémás részeken egy elágazást írnánk és lekezelnénk a máshogy működő adatbázis sajátosságát. Ez azonban meglehetősen rossz megoldás, mert egy magasabb szintű programrészből (üzleti logika) egy alacsonyabb szintű (adatbázis-elérés) problémájával foglalkozunk. A megoldás erre az lehet, hogy kiemelünk egy közös osztálykönyvtárat, amely elfedi előlünk az adatbázisok között fennálló különbségeket.

Vissza a tartalomjegyzékhez

Új Széchenyi terv
A projekt az Európai Unió támogatásával, az Európai Szociális Alap társfinanszirozásával valósul meg.

A tananyag az ELTE - PPKE informatika tananyagfejlesztési projekt (TÁMOP-4.1.2.A/1-11/1-2011-0052) keretében valósult meg.
A tananyag elkészítéséhez az ELTESCORM keretrendszert használtuk.