Tervezési minták
Sziasztok!
Alapvetően a tervezési mintákkal úgy vagyok, hogy ismerek párat, de van még jó sok, amit nem, és szívesen megismerkednék velük. Tudom, hogy van pár könyv a témában, illetve az interneten is fellelhető sok leírás, példa róluk, de (nem tudom más hogy van vele), nekem ezek nagyrészt homályosak, illetve sok esetben ellent is mondanak egymásnak.
Tehát ezzel a topiccal az lenne a célom, hogy kitárgyaljuk mi mire is való, milyen módon kell implementálni, esetleg ha ebben nálam okosabb emberek megosztanák a tapasztalataikat, azzal elősegítenék a mások, illetve saját magam okulását is.
■ Alapvetően a tervezési mintákkal úgy vagyok, hogy ismerek párat, de van még jó sok, amit nem, és szívesen megismerkednék velük. Tudom, hogy van pár könyv a témában, illetve az interneten is fellelhető sok leírás, példa róluk, de (nem tudom más hogy van vele), nekem ezek nagyrészt homályosak, illetve sok esetben ellent is mondanak egymásnak.
Tehát ezzel a topiccal az lenne a célom, hogy kitárgyaljuk mi mire is való, milyen módon kell implementálni, esetleg ha ebben nálam okosabb emberek megosztanák a tapasztalataikat, azzal elősegítenék a mások, illetve saját magam okulását is.
Konkrét kérdésre lehet
Rossz minta
"Nem tervezünk semmit, valahogy összelapátolunk valamit, majd kimagyarázzuk az ügyfélnél, úgyse ide fog visszajönni."
Ezzel akkor van baj, ha az ügyfél mégis visszajön...
Bocs a negatív példáért, de erre a témanyitóra ez jutott eszembe. Szerintem jobb lenne, ha előbb te bemutatnál párat, amit ismersz, hátha kedvet kap tőle más is.
ezek nagyrészt homályosak,
Ezek a minták best practice-ok, azaz sikeresnek bizonyultak számos probléma hatékony megoldásában. Nem szentírás, fel kell ismerni, mikor lehet/érdemes egyiket/másikat használni.
Legyegyszerűbb példa a Singleton tervezési minta. Bizonyos problémákra hatékony és egyszerű megoldást nyújt, ugyanakkor megvannak a maga hátrányai (tesztelés macerás, stb). Néha ezek a hátrányok annyira hangsúlyosak (pl annyira jó fejek vagyunk, hogy kifejezetten sokat szeretnénk tesztelni), hogy az általa nyújtott előnyök már nem adnak annyi pluszt, mint szeretnénk.
Tehát a mintákat nem ész nélkül kell használni, illik azt a néhányat tudni, és felismerni, hogy "hohó, minek gondolkozok én egy jó megoldáson, amikor erről a problémáról süt, hogy a Proxy tök jól működne!".
Végszó: There is no silver bullet
Hát ja kb erről szól a dolog,
Az adapter-t kimondottan szeretem, legalábbis elméletben minden olyan esetben használni kéne, amikor egy külső rendszert csatolsz a sajátodhoz. Ez azért van így, mert ha kicseréled a külső rendszert, akkor elég csak az adaptert kicserélned, nem kell könyékig túrnod a kódban. Ugyanígy verzió váltásnál ha az adapter tesztjei zöldek, akkor nagy valószínűséggel nem lesz probléma. Szóval ez laza csatoláshoz elég jó választás.
Van az observer, ami szintén laza csatoláshoz jó, javascriptben elég sűrűn használja az ember.
Van még abstract factory, factory method, builder, stb... ezekkel meg tudod azt csinálni, hogy lesz egy külön osztályod, ami felkonfigolja az objektumokat, és nem kell neked kézzel megcsinálnod, ha szükséged van egy-egy objektumra. A másik, ami fontos, hogy a factory dönti el, hogy milyen osztályt példányosít, neked csak annyi a lényeg, hogy egy adott interface-t megvalósítson ez a példány.
Van még a decorator, ami nekem személy szerint nem jön be annyira.
Aztán van még vagy három tucat, de nyilván nem fogom mindet felsorolni, nem is hiszem, hogy eszembe jutnának...
Elnevezések
Magam részéről a tervezési minták nagy hasznosságát ebbe látom. Egy-egy jól elnevezett osztály neve annyi plusz információt ad, hogy meg sem kell nézni az osztály forrását, mégis mindent tudsz róla.
Amint elkezdesz keretrendszereket használni, látni fogod, hogy ez sokat segít a rendszer megismerésében.
Teljesen jogos a felvetés,
class Singleton {
private static $instance;
private function __construct() {
}
private function __clone() {
}
private function __wakeup() {
}
public static function getInstance() {
if (!self::$instance) {
self::$instance = new User();
}
return self::$instance;
}
}
Ez eddig teljesen tiszta is. Factory-nál viszont nem egészen értem, mi az abstract factory és a factory method közötti különbség. A problémám főképp az, hogy könyvekben, tutorialokban néha-néha ellentmondanak egymásnak a példák, és nem tudom melyiknek is kéne hinni.
A Factory method elvileg valami ilyesmi lenne:
class FirstProduct {
}
class SecondProduct {
}
class ProductFactory {
public static function factory($type) {
$product = ucfirst($type).'Product';
if (class_exists($product)) {
return new $product();
} else {
throw new Exception('Invalid product');
}
}
}
Ez egy gyártó minta, elvileg ugyanazzal a felülettel, de más konkrét implementációval rendelkező objektumok gyártására szolgál.
Az Abstract Factory-t valaki el tudná magyarázni, hogy én is megértsem? :)
Közben nézegettem az Abstract
- először is, az abstract factory definiál egy abstract osztályt, amely megköveteli a gyártandó objektumok legyártását végrehajtó metódust
- abstract factory esetében nem egy általános gyártó metódus van, hanem minden objektum legyártásához külön metódust követel meg
Tehát valami ilyesmi:
interface Product {
}
class FirstProduct implements Product {
}
class SecondProduct implements Product {
}
// és itt jön a lényeg
abstract class AbstractFactory {
abstract public function getFirstProduct {}
abstract public function getSecondProduct {}
}
class ProductFactory extends AbstractFactory {
public function getFirstProduct() {
return new FirstProduct();
}
public function getSecondProduct() {
return new SecondProduct();
}
}
Ez az implementáció, nem a
Úgy általánosságban is szerintem érdemes elsősorban a problémát, célt felismerni a design patterneknél, amire megoldást adnak, nem az implementációt, különben nem tudod hol és miért kell bevetni.
Igen, valami ilyesmire
Ha már a Dependency Injection-t említetted, alapvetően ugye a célja az, hogy egy osztály függőségeit nem magában az osztályban példányosítjuk, hanem beinjektáljuk azt kontruktoron keresztül, metóduson keresztül (setter), vagy az objektum egy adattagján keresztül, így a rendszerünk komponensei sokkal egyszerűbben lecserélhetőek.
Üdv! Esetleg megkérhetlek,
Rendben, elnézést, eddig nem
Gyártófüggvény (factory
Elvont gyár (abstract factory):
Építő (builder):
pl: PDFBuilder, RTFBuilder, ... ugyanazt az interface-t implementálja, de más a kimenetük.
Prototípus (prototype):
Ha ismered a javascriptet, akkor elég világos, hogy miről szól.
Igen, olvastam a könyvet, a
Ööö, én ezt nem egészen így látom. A Builder egy-egy komplex objektumot épít, más-más módon. Egy egyszerű példa:
Prototípus:
ez tudtommal arra szolgál, hogy megspóroljuk az objektum példányosításába kerülő költséget, ezért létrehozunk egy prototípust, amelyet utána klónozunk. Ez főleg akkor hasznos, ha rengeteg azonos típusú objektummal dolgozunk:
Ööö, én ezt nem egészen így
[...]
Szerintem nem, a motorbicikli a leszármazottja kell legyen a járműnek. A színe, rendszáma tulajdonság, de az, hogy motor, vagy autó, az a viselkedését befolyásolja. Gondolj egy turnLeft()-re...
Szerintem nem, a motorbicikli
Ebben igazad van, az, hogy motorbicikli, nem tulajdonság. A példa ilyen szempontból hibás, de ha vegyük ki a type-it a képletből, és így szerintem érthető lesz.
A Builder egy komplex objektum felépítésére, felparaméterezésére koncentrál, lényegében egy egyszerűbb felülelet kínál a felépítésére. A factory ezzel szemben egy feltétel alapján példányosít és visszaad egy (akár egyszerű akár komplex) objektumot, de nem törődik azzal, annak úgymond "felépítésével" mint a factory. Egy talán érthetőbb példa:
Te hogyan implementálnád ezt factory alkalmazásával?
Erre minek külön osztály?
Mármint ha jóval
A Form osztályból hogyan származna a LoginForm osztályod?
Ez nem alami szép megoldás.
Egy olyan factory, ami egyfajta objektumot ad vissza? Na erre szolgál pont a Builder.
In the Factory pattern, the factory is in charge of creating various subtypes of an object depending on the needs.
The user of a factory method doesn't need to know the exact subtype of that object. An example of a factory method createCar might return a Ford or a Honda typed object.
In the Builder pattern, different subtypes are also created by a builder method, but the composition of the objects might differ within the same subclass.
To continue the car example you might have a createCar builder method which creates a Honda-typed object with a 4 cylinder engine, or a Honda-typed object with 6 cylinders. The builder pattern allows for this finer granularity.
Erre kérlek írj egy példát. És arra is, hogy szerinted miben különbözik a kettő. Tényleg kíváncsi vagyok a te meglátásodra.
A HTML-es példádra pont a Decorator pattern való. Van például egy TextInput osztályod, illetve egy HTML5Decorator és egy XHTML osztályod. Attól függően, hogy hogy akarod megjeleníteni, a HTML5Decoratorral, vagy az XHTMLDecoratorral dekorálod a TextInput-ot.
A Form osztályból hogyan
Pontosan úgy, ahogy írtad.
Lehet, de ugyanúgy használható...
A könyv szerint, amit olvasok nem erre szolgál a builder, és a Gamma és társai féle Design patterns azért nekem többet nyom a latban, mint egy becopy-zott idézet.
Felépítésében nem különbözik a factory és a inversion of control container, annyi a különbség az ioc-nál, hogy a használati helyénél a container-t adod át, és nem a kész példányt. Én legalábbis nem tudok más eltérésről.
Ezt kifejtenéd, én teljesen máshogy látom. A Decorator új tulajdonságok felvitelére jó, mondjuk ha van egy képed, akkor dekorálhatod egy kerettel, stb... A html5 meg xhtml meg két külön megjelenítési mód, ezeket nyilvánvalóan abstract factory-be kell kiszórni, ill. builder-rel kell megcsinálni magát az űrlapot. De erre írok is példát:
Azt hiszem a példa elég világosan mutatja, hogy mi a builder, és a factory között a különbség, ill. talán rávilágít arra is, hogy a IoC container (vagy DIC) inkább egy interface, ami nem szabja meg, hogy mi történjen a megvalósításon belül, tehát a container lehet factory, paraméterezett builder, singleton, vagy bármi egyéb, ami megfelel a container interface-nek.
Ez szerintem így még mindig
Nem a fent vázolt a "hivatalos" megvalósítása a builder patternnek (legalábbis a wikipedia és a rá épülő tartalmak nem így mutatják be - itt nincs abstract, meg concrete builder), de szerintem ez jól megmutatja mire jó. Illetve azt is, hogy ezek a patternek mennyire a probléma megoldásáról szólnak, nem a megvalósításról, valamint hogy az egyes patternek között milyen átfedések vannak. Ezért sem érdemes ezeket bemagolni.
Ööö, én ezt nem egészen így
Ez azért van, mert kevered a buildert a factory-vel. Amit te írsz azt két factory-vel lehet megcsinálni, és nem két builder-el. Ez is olyan kicsit, mint a hagyományos nyelvtanulás, nem jó keverni a szavakat... :-)
Lásd BlaZe hozzászólására
factory = gyár, builder =
Szerintem elég világos, a
Én bringákat építek, de
Akkor majd tudsz nekem jó
Kérdés h milyened van most?
Egyébként meg nem csak a nyereg lehet a probléma, hanem a rossz vázgeometria, helytelen ülésmagasság, stb
Fentebb bemásoltam egy angol
Tervezési minták könyvből másolva:
Építő (Builder) minta célja
Az összetett objektumok felépítésének függetlenítése az ábrázolásuktól, így ugyanazzal az építési folyamattal különböző ábrázolási folyamatokat hozhatunk létre.
Fentebb bemásoltam egy angol
Ott kevered, hogy a factory konrkét, a builder meg absztrakt/elvont.
itt nyilvánvalóan factory kell, mert konkrét példányt hozol létre:
Ott kevered, hogy a factory
Olvasd el a design patterns könyvet mégegyszer, keress rá neten, nem tudom miért hajtogatod, mindenhol le van írva nagyon egyszerűen, hogy mi is ez. A Builder is konkrét példányt hoz létre. Ezen felül ezt a példát már nem én írtam, hanem bemásoltam egy Builder-ról szóló cikkből...
Igazából én már nem tudom mit írjak neked, mert nem igazán vagy hajlandó tudomásul venni semmit. Tipikus példája az én mindent tudok esetnek. Rengeteg példát írtam, és másoltam be több helyről is leírást, hogy mi mire való. Te csak hajtogatod, hogy nem jó, azt, hogy miért nem, igazából példával nem támasztod alá. A neten rengeteg példa van rá, parancsolj:
https://github.com/kevbradwick/php-design-patterns/blob/master/Patterns/Builder/ProductBuilder.php
https://github.com/cbergau/PHPDesignPatterns/blob/master/builder.php
http://tinyweb.blogspot.hu/2012/07/builder-design-pattern-using-php.html
http://www.newthinktank.com/2012/09/builder-design-pattern-tutorial/
https://github.com/sinevar/php-design-patterns/blob/master/builder-design-pattern/implementation1/classes/WardrobeBuilder.php
http://architects.dzone.com/articles/does-builder-design-pattern
Különbség a factory és builder pattern között:
https://www.google.hu/search?q=factory+builder+k%C3%BCl%C3%B6nbs%C3%A9g&rlz=1C1CHMO_huHU503HU503&aq=f&oq=factory+builder+k%C3%BCl%C3%B6nbs%C3%A9g&aqs=chrome.0.59j62l3.8445&sourceid=chrome&ie=UTF-8https://www.google.hu/search?q=factory+builder+k%C3%BCl%C3%B6nbs%C3%A9g&rlz=1C1CHMO_huHU503HU503&aq=f&oq=factory+builder+k%C3%BCl%C3%B6nbs%C3%A9g&aqs=chrome.0.59j62l3.8445&sourceid=chrome&ie=UTF-8
Idézet:
Az elsődleges különbség, hogy a Builder minta az összetett objektumok lépésről lépésre való
létrehozását helyezi középpontba. Az Abstract Factory esetében a termékobjektum-családok a
hangsúlyosabbak (akár egyszerű, akár összetett). A Builder minta utolsó lépésben visszaadja a
terméket, azonban az Abstract Factory minta, ami azt illeti azonnal.
http://stackoverflow.com/questions/757743/what-is-the-difference-between-builder-design-pattern-and-factory-design-pattern
Idézet:
https://groups.google.com/forum/?fromgroups=#!topic/comp.object/20s5FN3qUTE
Idézet:
Abstract Factory, every method call returns its own little object.
complex object so that the client just requests a configuration and the
builder directs the logic of building it. E.g The main contractor
(builder) in building a house knows, given a floor plan, knows how to
execute the sequence of operations (i,e. by delegating to subcontractors)
needed to build the complex object. If that logic was not encapsulated in
a builder, then the buyers would have to organize the subcontracting
themselves ("Dear, shouldn't we have asked for the foundation to be laid
before the roofers showed up?")
http://www.coderanch.com/t/149924/java-Architect-SCEA/certification/Difference-Abstract-Factory-Builder-Pattern
Idézet:
Builder pattern is to decouple the representation from the complex construction proces, so that the same construction process can be used for different representations.
Google-ban rengeteget találsz még... De gondolom úgy is az lesz a válasz, hogy ők is rossz példákat írtak.
De nézzünk még egy számodra hitelesnek tartható forrásból is, Gamma féle Design Patterns könyv:
Cél: Az összetett objektumok felépítésének függetlenítése az ábrázolásuktól, így ugyanazzal az építési folyamattal különböző ábrázolásokat hozhatunk létre.
...
Kapcsolódó minták
Az Elvont gyár annyiban hasonlít az Építőhöz, hogy az is összetett objektumok megalkotására képes. A legfőbb eltérés közöttük, hogy az Építő minta az összetett objektumok lépésről lépésre történő létrehozását helyezi előtérbe, az Elvont gyár pedig termékobjektum-családokra helyezi a hangsúlyt (legyenek azok egyszerűek, agy összetettek). Az Építő utolsó lépésként adja issza az objektumot, az Elvont gyár viszont azonnal.
Elvont gyár annyiban hasonlít
Bahh... :D Miért kell mindent kényszeresen magyarítani a szakkönyvekben? Ki használt ilyen kifejezéseket valaha munka közben? :)
Szóval szerintem amúgy onnan kéne közelíteni a vitában, hogy mire való a 2 pattern, nem az implementáción vitatkozni. Aztán kiviláglana a különbség. Tökmind1, hogy absztrakt vagy nem, másra használjuk őket.
Szóval szerintem amúgy onnan
Már ő is leírta az idézeteiben, hogy mire valók. A builder összetett objektumok felépítésére jó, és függetleníti a felépítésüket az ábrázolástól. Az ábrázolást abstract factory-vel lehet hozzácsapni, és attól függően változik, hogy milyen konkrét factory példányt használsz. Szóval a builder irányítja az abstract factory-t, tehát ő eggyel magasabb absztrakciós szinten van. Én legalábbis így használom, mert így látom értelmét, és a könyvben is kb ez van.
Az ábrázolást abstract
Az ábrázolást már megvalósítja az osztály, amiből a builder objektumot fog gyártani. Lehet kombinálni a kettőt, ahogy te a példádban tetted, de alapvetően mint két független pattern beszélünk róluk. A Builder-t inkább a Composite patternnel szokták együtt használni... Ez is le van írva a Tervezési minták könyvedben.
Nem igazán érdekelnek ezek a
Nem igazán érdekelnek ezek a
Ez ám a hozzáállás. Tehát ami nem téged igazol az téged nem érdekel. Egyébként a Design Patterns könyvből is kimásoltam, oda is tisztán és érthetően le van írva (példa is van ott), hogy mi a különbség, ami az összes többi linken is ott van.
Nem siklottam át felette, ugyanazt csinálja a Builder-ed, mint amit eddig leírtam számtalanszor, csak te pluszban beinjektáltad egy factory-ba. Amit nem egészen értek, mert a factory ugye hasonló (de más) objektumok legyártására való, a builder pedig egyféle objektum másképpen való legyártására.
Jó, szerintem lapozzunk.
Ez volt már? Ugyan angolul
Ugyan angolul van, de elég sok DP-t felsorol és részletez.
Learning JavaScript Design
webproghu
Nem muszáj őket használni, ha
»Nem muszáj őket használni,
Itt mire gondolsz?
Mindenre megpróbálod ráhúzni
Nem muszáj őket használni, ha
Nem maguk a minták ellentmondásosak, hanem a könyvek, példák, amik őket magyarázzák. Fentebb lehet is látni, hogy sok ember másként értelmezheti őket. Ezeknek az alkalmazása nyilván nem kötelező, jó ismerni őket, mert adott helyzetben hasznosak lehetnek. Én inkább ahhoz hasonlítanám őket, hogy ha házat építesz, akkor hogyan használd a kalapácsot és a szöget, ha a tetőd építed, ha a teraszt, vagy ha a kerítést. :)
Nem maguk a minták
Úgy, hogy egy minta nem
Azért ez egy kicsit sántít.
A magam részéről úgy
Valahol egyetértek veled, én sem úgy indulok neki egy kódnak, hogy ide hű de jó lenne ez meg ez a minta, hanem csinálom, ahogy jól esik, aztán vagy felismerem, vagy nem, hogy milyen mintát használok. Igazából már lassan a nevüket is elfelejtem. A solid elvek meg a refactoring sokkal többet ad a gyakorlatban, mint ezek a minták.
Így van
Ja egyébként TDD remekül