Názory ke článku Návrhový vzor Factory v C++
Musím se přiznat, že napoprvé jsem to úplně nedal, ale napotřetí jsem to už pochopil :smile4: No každopádně po dlouhé době článek na programujte, který má hlavu a patu, a nad kterým jsem se musel opravdu zamyslet. :smile2: Kruci, jenom aby to nebylo tím, že jsou dvě ráno :smile14:
19. 12. 2007
ze zacatku dobry, ale od Genericke Factory jsem pomalu prestaval chapat. Kazdopadne konecne dalsi clanek, ktery mi dal neco noveho a ktery byl napsan fakt dobre. :smile2:
To nickJartin: No je pravda ze cast Genericke Factory uz je dost narocna, hlavne pre ludi ktory sa templates velmi nevenuju.Pocital som tam uz s urcitymi znalostami. Rozmyslal som ci rozviest aj principy ktore som pouzil, ale to by asi bolo na samostatny serial. Ak teda viacery nepochopia poslednu cast, nic sa nedeje.. Ta posledna cast je urcena asi skor uz skusenejsim koderom v c++. Myslim ze to nemozem chciet od ziadneho zaciatocnika aby ju pochopil. Ak sa tak vsak stalo a nasiel sa niekto taky, tak pred nim skladam klobuk.
Opravdu moc pěkný článek :smile2: . Hlavně mě zaujalo to zřetězení šablon, určitě to někde použiju. Jinak takový seriál o templates by vůbec nebyl k zahození, nebo taky články o jiných návrhových vzorech.
To Jonyzz:
Skus pridat toto zelanie do sekcie 'Clanky na prani'
http://programujte.com/index.php?akce=navrhy
25. 12. 2007
Christ ! Takhle se to vubec nepise, design pattern factory nesmi byt zavisly na zadnem jinem objektu, to znamena ze se nesmi v zadne metode pouzivat new Abc(); ale musi se do konstruktoru zapsat napriklad char* object, coz bude pointer na objekt Abc(), aby bylo pozdeji mozne pouzit stejnou metodu pro vytvoreni jineho objektu, treba Def(). Doporucil bych nejprve se naucit design patterny a c++, teprve pote (nejmene za 5 let) o tom zacit pozvolna psat.
PS: ten vas stupidni wysiwyg v Opera browseru nemusi mit v javascriptu az 5-ti sekundovy timeout predtim, nez se zobrazi text, ta chyba se totiz musi obchazet jen ve FireFoxu a to se dela trochu jinak, nez tupym zdrzovanim uzivatele ! To neumite nikdo ani napsat cross-browser wysiwyg, prestoze primo na Mozilla.org je priklad, ktery ma ten FF bug dobre osetren?
To ~: Chapem vase rozhorcenie. Totizto po vasom prispevku som si uvedomil ze pojem Factory je pre tento clanok zavadzajuci. Mozno vadi ze v clanku je popisany presne vzor ktory je v GOF. Prva Factory je pisana podla Alexandrescu Modern C++ Design. To tvorilo pre mna zaklad a drzal som sa ho s toho dovodu aby som presne nenapisal nejaku hlupost. Tym padom sa ospravedlnujem ze som cerpal z nespravneho zdroja. Priznam sa vsak ze z mojej hlavy uz je to zabalenie do sablon na konci clanku, ale princip som nechal nezmeneny. Cize ak je chybny jeden, su chybne oba. Mohol by som vas preto poziadat o spresnenie problemu? Mohli by ste teda uviest nejaky kratky priklad? Uplne respektujem vase pripomienky.
20. 1. 2008
To ~: Možná by pan neumímsepodepsat mohl nám nevzdělaným říci, jaká jsou pravidla používání návrhových vzorů. Já osobně žádná neznám. Návrhové vzory jsou podrobně zanalyzovaná řešení často se opakujících problémů v programátorské praxi, ale rozhodně ne patent na moudrost. Nikdo nikomu nebrání si je přizpůsobit dle obrazu svému a odchýlit se od řešení, které navrhli GOF.
Snažil jsem se pochopit Vaši výtku, ale nikde jsem v továrně (ani první ani generické) nenašel žádný kód typu new Abc();. Je tam pouze volání tovární funkce přes zaregistrovaný ukazatel, která vrací ukazatel na abstraktního předka (v knížce Andreje Alexandrescu je to dokonce obecněji funktor, nejen ukazatel).
Jediné, co mě napadá, že jste jí mohl myslet, je fakt, že továrna musí znát typ abstraktního předka. Pokud jste správnou implementací myslel, že továrna bude vracet char * a všichni, kdo ji používají, budou tento ukazatel přetypovávat, tak jste IMHO prase. Pokud jste to tak nemyslel, tak nevím, o čem píšete. Navíc továrna pracuje pouze s ukazatelem, takže překladači ke štěstí stačí forward deklarace "class Obrazek;" a továrna nemusí být závislá (tím myslím, že vůbec nemusí znát, jak je třída Obrazek deklarována).
Článku bych osobně vytkl asi pouze jednu věc, a to "brojení" proti stringu jako klíči a obecné doporučení používat výčtové typy, které je odvozené z neobecného případu koncovek souborů obrázků. Použití výčtových typů znamená, že v programu je pouze jedno místo, kde se definují konstanty, a to je přesně to, čemu se továrny snaží vyhnout. Zavedení nového typu pak znamená vytvořit nový modul, který typ definuje, a někde jinde nezapomenout vytvořit pro typ konstantu.
Pokud budu tímto způsobem rozšiřovat nějakou knihovnu, ani nemusím mít možnost výčotvý typ změnit. Ten by byl deklarovaný někde uvnitř knihovny. V takovém případě knihovna nemůže jako klíč používat výčtový typ a musí jako součást své dokumentace zveřejnit nějaký jiný postup, jak si vytvořit jednoznačný klíč pro uživatelsky definovaný typ. Textová jmenná konvence odvozená např. ze jména třídy nemusí být úplně špatný nápad.
Používání int klíčů v tomto případě znamená používat nějaký systém generátorů jednoznačných konstant typu Microsoftího GUID, který vytváří klíč, tuším, z aktuálního času, MAC adresy síťové karty a pravděpodobně z aktuální úrovně kosmického záření :smile1:
Také jsou případy, kdy textový klíč je přirozené řešení. Pokud například uložím nějakou objektovou strukturu do XML, a pak se ji pokusím načíst, jsou textové údaje načtené z XML rozumným klíčem do továrny.
Takhle mohou pracovat SOAP knihovny, které při deserializaci objektů potřebují podle příchozí SOAP zprávy objekt vytvořit. Mimochodem, to je také přiklad, kdy se nehodí výčtový typ, protože knihovna dopředu vůbec neví, jaké objekty bude serializovat. To je dané až specifikací SOAP protokolu.
22. 1. 2008
Ještě jsem přemýšlel a musím trochu přehodnotit svůj předchozí názor. Článku je potřeba vytknout více věcí, nejen práce s výčtovými typy.
Smyslem továrny je několik věcí. Zaprvé je to možnost snadného rozšiřování o nové uživatelsky definované typy. To vyžaduje, že je možné si typ definovat a zaregistrovat odděleně na různých místech programu. Pokud by bylo jen jedno možné místo, jakékoliv rozšíření znamená zásah do původního zdrojáku (tam kde se typy registrují), a to nemusí být vždy možné (pokud jsem původní kód nepsal já, např. knihovna).
Dalším smyslem továrny je typy registrovat dynamicky. Například s Vaším příkladem obrázků, pokud budu chtít podobně jako GIMP nebo Photoshop mít možnost rozšířit počet podporovaných typů obrázků pomocí pluginů, je potřeba si typ v továrně zaregistrovat za chodu programu podle informací načtených ze zavedeného pluginu. Tuhle podmínku továrna pochopitelně nemusí splňovat, pokud dynamickou registraci nepotřebujeme. Ale první podmínka stejně pravděpodobně bez ní splnit nepůjde.
Posledním a ne nejmíň podstatným smyslem továrny je snížit závislosti mezi jednotlivými moduly. Pokud místo továrny použiji switch-case konstrukci, tak tento modul musí znát všechny v systému vyráběné typy, tzn. musí "includovat" všechny příslušné headery. Továrna naopak díky možnosti registrace typu umožní modulu, aby se sám zaregistroval a výrobní funkce továrny vůbec nemusí znát definici kteréhokoliv registrovaného typu.
Z pohledu těchto tří hledisek je první továrna napsaná dobře. Umožňuje dynamickou registraci z různých míst programu, pro svou činnost nepotřebuje znát jednotlivé typy, pouze volá zaregistrovanou tovární funkci.
Co je špatně, je použití. Jeden enum a registrace všech typů na jednom místě. Tím vzniklo úzké hrdlo závislostí, protože tento modul, kde se registrace provádí, musí všechno znát. Rád bych věřil, že to je pouze ilustrační příklad, ale následující generická továrna působí, že tohle je považováno za normální použití.
Generická továrna totiž je opět úzké hrdlo závislostí, protože při vytvoření továrny je potřeba znát tovární funkce opět všech používaných typů, které je logické mít definované v modulu, který typ definuje. Mohl bych použít pouze forward deklarace továrních funkcí, ale pak pro každý nově zaváděný typ potřebuji nezapomenout forward deklaraci do registračního modulu dopsat. A ať s nebo bez forward deklarace nesmím zapomenou dopsat nový typ do deklarace továrny.
Tedy generická továrna nesplňuje ani jednu z podmínek. Pro zavedení nového typu je potřeba upravit kód, kde je továrna deklarovaná, a typ se tak nemůže zaregistrovat sám. Typ nelze registrovat dynamicky. A pokud nebudu chtít dopisovat deklarace továrních funkcí, tak se stane úzkým hrdlem závislostí. Suma sumárum, generická továrna je sice roztomilá šablonová konstrukce, ale oproti switch-case konstrukci nepřináší vůbec žádné výhody (akorát je možno pracně zrušit závislosti). Domnívám se tedy, že její použití je vlastně zbytečné a pro většinu lidí bude switch-case konstrukce přehlednější (a i u té můžu zrušit závislosti pomocí forward deklarací), než takováto nečitelná šablona smíchaná s makry.
Nojo nemozem povedat na to co sa napisalo vyzsie ani krive slovo. Snad je jasne ze clanok bol pisany experimentalne. Prave o toto mi islo, vyvolat nejaku takuto diskusiu. Je pravda ze taketo veci by som asi mal skor pisat do diskusii, lenze tu diskusie velmi nefunguju :) respektive malokto dokaze diskutovat k veci a kto vie ci by sa mi dostala takato rozsiahla reakcia. ;-)