A legegyszerűbb módja ennek, ha van egy factory osztályunk, annak pedig egy olyan eljárása, ami egy paraméter alapján "legyártja" a kívánt objektumot.
Ha például egy online fizetési módot szeretnénk megvalósítani PHP segítségével, az így fog kinézni:
class Payment {
public $data;
function __constructor($data) {
$this->data = $data;
}
function process() {}
function getResult() {}
}
class CreditCard extends Payment {}
class PayPal extends Payment {}
class PaymentFactory {
const CREDIT_CARD = 1;
const PAYPAL = 2;
function createPayment($data) {
switch ($data['type']) {
case CREDIT_CARD :
return new CreditCard($data);;
case PAYPAL :
return new PayPal($data);
default :
return new Payment($data);
}
}
}
// kliens kód
$data = $_POST;
$pay = PaymentFactory::createPayment($data);
$pay->process();
Persze ez egy nagyon kigyomlált kód az érthetőség kedvéért, validálás nélkül használja a $_POST változót, de az majd egy másik történet lesz. Mint látható az, hogy melyik fizetési mód lesz példányosítva egy felhasználótól érkező form alapján dől el és ez meghatározhatja a következő lépést is, például a kártyaadatok bekérése vagy az átirányítást a PayPal fizetőoldalára. A kliens kódnak csak arról kell tudnia, hogy a form milyen értékeket adhat át az asszociatív tömb "type" részeként. Jelen esetben 1-et vagy 2-t, de tulajdonképpen ez a kód nagyon rugalmas, kibővíthető több fizetési móddal is. Továbbgondolva egyetlen hátránya, hogy a sok leaf osztály miatt nagyon megnőhet az a switch blokk és ugyan nem valósult meg kódduplikáció, de mégis szeretem kerülni a túl sok if-et és switch-et, ha objektumorientált programozásról beszélek.
Nézzük, mi van akkor, ha a kliens számára biztosítani szeretnénk, hogy a saját osztályait gyárthassa a saját feltételei alapján? Erre találták ki az Abstract Factory mintát. Az alábbi példa egy kártyát és egy virtuális fizetőeszköz implementálását várja el a kliens osztályától.
abstract class AbstractPaymentFactory {
abstract function getCardPayment();
abstract function getVirtualPayment();
}
interface PaymentInterface { function process(); }
class AmazonPaymentFactory extends AbstractPaymentFactory {
function getCardPayment() {
return new AmazonCreditCardPayment();
}
function getVirtualPayment() {
return new AmazonMoneyBookersPayment();
}
}
class EbayPaymentFactory extends AbstractPaymentFactory {
function getCardPayment() {
return new EbayCreditCardPayment();
}
function getVirtualPayment() {
return new EbayPaypalPaypent();
}
}
// a fizetési módok osztályai
class EbayCreditCardPayment implements PaymentInterface { function process() {} }
class EbayPaypalPaypent implements PaymentInterface { function process() {} }
class AmazonCreditCardPayment implements PaymentInterface { function process() {} }
class AmazonMoneyBookersPayment implements PaymentInterface { function process() {} }
// példányosítás
$factory = new AmazonPaymentFactory();
if($_POST['type'] == 1)
$pay = $factory->getCardPayment();
else
$pay = $factory->getVirtualPayment();
$pay->process();
Ha olyan vagy mint én és szereted rendben tudni a kódodat, akkor most megszólalt a szirénád, mivel sokféle osztály esetén rengeteg kód duplikáció keletkezik fölöslegesen. A következő minta, ami megoldja ezt a problémát, a Decorator Pattern, de azt majd egy következő bejegyzésben...
Figyeljük meg, hogy mivel a PHP nem képes a visszatérési értékek type casting-jára, nem tudjuk elvárni a klienstől, hogy a getCardPayment() és getVirtualPayment() visszatérési értékei a PaymentInterface egyik megvalósítása legyen. Ez a nyelv hibája, amit az osztályunk dokumentációjával kell kompenzálnunk és megkövetelnünk, hogy minden esetben ilyen osztállyal tárjen vissza a kliens megvalósítása is.
A bejegyzés normálisan beállított és kibővített Drupal-al (code tag behúzza a tabokat és színez is):
http://sandor.czettner.hu/blog/11/07/18/objektumgyar-minta
- zoner blogja
- A hozzászóláshoz be kell jelentkezni
- 1807 megtekintés
Hozzászólások
indentald a kodot, legyszi, mert igy olvashatatlan.
- A hozzászóláshoz be kell jelentkezni
És a saját oldalamat meg senki nem olvassa majd, mert ide a hupra soronként copypaste-zok tabokat?
- A hozzászóláshoz be kell jelentkezni
"A bejegyzés normálisan beállított és kibővített Drupal-al (code tag behúzza a tabokat és színez is):"
a hup.hu kicsit sárga, kicsit savanyú, de a miénk.
- A hozzászóláshoz be kell jelentkezni
if ( akarom ( nagyon ) ) {
indentálás.működik = true ;
// mily meglepő
} else {
while ( !értem ( a_lényeget ) {
elolvasom ( a_szerkesztési_tippeket ) ; // itt: http://hup.hu/filter/tips
}
}
amúgy: ez a "normálisan beállított és kibővített" Drupal milyen verzió?
(rejtett subscribe)
- A hozzászóláshoz be kell jelentkezni
"Figyeljük meg, hogy mivel a PHP nem képes a visszatérési értékek type casting-jára, nem tudjuk elvárni a klienstől, hogy a getCardPayment() és getVirtualPayment() visszatérési értékei a PaymentInterface egyik megvalósítása legyen. Ez a nyelv hibája, amit az osztályunk dokumentációjával kell kompenzálnunk és megkövetelnünk, hogy minden esetben ilyen osztállyal tárjen vissza a kliens megvalósítása is. "
"ezért a másik fejlesztő által írt kódot, ami az én osztályaimat használja, kliens kódnak fogom nevezni."
Ha jol ertem te vagy a facktory szerzoje, es aki hasznalja az a kliens.
Elvarjuk toled, mint a factary mogott levo kod szerzojetol, hogy ne szopassd a clienseidet. :)
Mivel peldadban a konkret facktorikat a cliens hozza letre, igy sajat magat szivathatja csak. :) . Hacsak itt nincs meg egy cliense a cliensnek... ekkor lasd elzo elvaras.
A legtobb cliens, talan megbizik benned, vagy megelegszik, ha van process() implementalva, az interface tenyleges implementalasa teljesen lenyegtelen szamara. See also: <duck typig>
A bizalmatlanabbak mindig ellenorozhetik, hogy a megfelelo interfacet implementalja -e a kapott peldany. pl.: if($pay implements PaymentInterface) {$pay->process();} eles { echo "Your factory is s*cks! PaymentInterface not implemented!
"; die();}
A rendszeres bizalmatlankodok kiszervezhetik akkar fuggvenybe is. :)
Amit nem lehet megirni assemblyben, azt nem lehet megirni.
- A hozzászóláshoz be kell jelentkezni
facktory?:D
is sucks?
azt hittem a diplomahoz kell egy nyelvvizsga :)
- A hozzászóláshoz be kell jelentkezni
összetévesztette a flepnijével
- A hozzászóláshoz be kell jelentkezni
Hogyne kene. De a helyesirasom mindig is legendas volt. :)
Amit nem lehet megirni assemblyben, azt nem lehet megirni.
- A hozzászóláshoz be kell jelentkezni
oke, de mas azert egy szot ket k -val irni, vagy ket l-lel, vagy egy ly/j -t elrontani, mint egy nyelvtani hibat veteni angolban :-)
- A hozzászóláshoz be kell jelentkezni
Láttam olyan embert középfokú C típusú angol nyelvvizsgával, aki két szót tudott: yes/no. Nem mérvadó. :C
- A hozzászóláshoz be kell jelentkezni
Én is mostanában készülök Zend PHP Certification-t lerakni. Ha érdekel akkor megoszthatnánk az eddigi tapasztalatainkat, tudásunkat.
- A hozzászóláshoz be kell jelentkezni
Igen, erre van ez a blog, figyelem a nálam jobbak reakcióit, az Unit test-es bejegyzésem hozzászólásaiból is sokat tanultam. :)
- A hozzászóláshoz be kell jelentkezni