Čistý Programátorský Experiment – moje řešení

Školení, která pořádám

Nejprve si přečtěte zadání. Zadání podle mě klade jednu zavádějící otázku:

Jak docílit toho, aby metoda load mohla vytvořit objekt a nastavit mu read-only vlastnosti body, headers a thumbnail na hodnoty načtené z databáze?

Ukázky kódu nicméně nevyžadují, aby metoda load vracela právě instanci WebPage. Logičtější mi proto přijde, aby třída WebPageStorage byla potomkem WebPage a metoda load vracela instanci své třídy. Přistupovat se bude tedy přes tuto třídu, která si sama rozhodne, jestli data vrátí z databáze nebo si je načte.

<?php
class WebPage {
    var $url;
    private $data = array();
    
    protected function getData() {
        if (!$this->data) {
            $this->data["body"] = file_get_contents($this->url);
        }
        return $this->data;
    }
    
    function __get($name) {
        $this->getData();
        return $this->data[$name];
    }
    
    function __set($name, $value) {
    }
    
}

class WebPageStorage extends WebPage {
    
    static function load($url) {
        $return = new self;
        $return->url = $url;
        return $return;
    }
    
    function __get($name) {
        if (!$_SESSION["WebPageStorage"]) {
            $_SESSION["WebPageStorage"] = $this->getData();
        }
        return $_SESSION["WebPageStorage"][$name];
    }
    
}
?>

Co se změn týče, doporučil bych třídě WebPage přidat konstruktor a odebrat možnost změnit url (jeden objekt by měl reprezentovat jen jednu stránku) a ze statické metody WebPageStorage::load udělat také konstruktor.

Jakub Vrána, Řešení problému, 29.10.2009, diskuse: 23 (nové: 0)

Diskuse

ikona David Majda:

Pokud by WebPageStorage měla být potomkem WebPage, určitě bych ji přejmenoval. Mezi podtřídou a nadtřídou by měl platit "is-a" vztah a "WebPageStorage is-a WebPage" zní divně. Lepší název by byl třeba StoredWebPage, CachedWebPage apod.

Megaloman:

StoredWebPage is a WebPage, ale is a vyjadřuje vztah generalizace/specializace, a ta tady není...

ikona David Majda:

Mezi těmi dvěma třídami JE dle kódu vztah specializace - WebPageStorage je WebPage, která má navíc statickou metodu "load" a kešuje svá data v session. WebPageStorage dodržuje rozhraní definované třídou WebPage.

Úplně jiná otázka je, zda použití dědičnosti/specializace je vhodné řešení zadaného problému. Domnívám se, že není. O tom můj příspěvek ale nebyl.

Jirka:

David ma samozrejme pravdu. Aniz bych se dival na obsah trid WebPage a WebPageStorage, tak je spatne pouzita dedicnost naprosto zrejma. V tomto pripade by stacilo prejmenovat nazev tridy WebPageStorage, aby to dostalo smysl.
Jak rikal David neni to hodnoceni spravneho reseni problemu, ale spatneho pojmenovani tridy.

Megaloman:

S konstruktorem souhlasím - měl by při vzniku přijmout url, které by mělo být dále neměnné.

Ale s řešením jako takovým ne, protože WebPageStorage by čistě programátorsky experimentálně neměl být potomkem WebPage, byť zadání k tomu svádí ;-).

Tomáš Fejfar:

Chybí mi tam možnost snadno vymenit persistentní vrstvu místo session třeba za databázi... Rozhodně mi to nepřijde jako "čisté" řešení. Spíš jako "jednoduché a perfektně funkční" řešení :D

jah rastafari:

Jezismarja, tohle je to uplne nejstrasnejsi reseni z pohledu objektove cistoty jake lze udelat. Fuj, fuj, fuj, hnus. Jakube Vrano, styd se, a podivej se do komentaru pod clankem vyzyvatele. Tam je sepsano spravne reseni (ja ho nepsal, ale presne tak bych to udelal). Tvoje reseni placa dohromady nekolik naprosto nesouvisejicich veci. Jak muze byt WebpageStorage potomkem WebPage? Achjo, samozvana elita ceske php sceny je cim dal vic ubozejsi.

petr:

Jahu, sestup z obláčku a řekni konkrétně, proč Jakubovo řešení by nemohlo být minimálně inspirativní

jah rastafari:

Ukolem je najit co nejcistsi objektove reseni. Je videt, ze Jakub bud nezna, nebo dela, ze nezna, takovou divnou vec - navrhove vzory se ji rika. Vic neni treba dodavat.

Martin:

Jakub především neumí objektově programovat. To snad je z jeho blogu dávno zřejmé!

ikona JackeLee:

Což neumí nikdo, jen jsou lidé co si myslí, že to možné je ;-)

Voy:

Dedicnost v tomhle pripade opravdu nepovazuji za vhodne reseni, michaji se tu dve rozdilne zodpovednosti, ktere by proste mely byt rozdeleny do ruznych trid a ne resene pomoci specializace. Nemam patent na rozum, ale tohle reseni proste smrdi.

finc:

Z pohledu objektoveho navrhu je toto skutecne spatne.

Potomek by mel maximalne rozsirovat vlastnosti sveho predka, nikoli obsahovat zasadni funkcionalitu.

Existuje nekolik variant, jak toto zadani vyresit. Bohuzel, David neuvedl priklady, kde a jak chce WebPage pouzivat. Z tohoto pohledu je pak docela problem navrhnout co nejlepsi reseni.

Kazdopadne existuje nekolik jasne danych pravidel:
1. WebPage by nemel vedet nic o zpusobu nacitani
2. Zpusob nacitani by melo byt dobre vymenitelne bez zmeny kontraktu

Me osobne se asi nejvice libi pouziti navrhoveho vzoru strategie.

RoW:

Ahojte...asi trochu offtopic ale chcel by som sa spytat, ci maju v OOP PHP nejaky zmysel Interfaces...v inych jazykoch ich miesto a dolezitost chapem ale v PHP velmi nie. Co sa tyka aktualnej temy, tak by som sa priklanal taktiez k vzoru strategie alebo vzor dekorator by sa tam dal tiez uplatnit ;-)

Juan:

Mají tam úplně stejný význam jako v jiných jazycích. Tvůj dotaz nechápu :)

RoW:

Zle som polozil otazku :-)takze este raz...takto to bolo myslene: "pouzivate Interfaces v OOP PHP?" ;-)

Jiří Knesl:

Ano, bez interfejsů bych se v žádném případě neobešel.

Juan:

Používám je. Význam mají především u větších projektů nebo frameworků, atd. První příklad, který mě napadá je třeba routování v Nette Framework. Součástí frameworku je perfektní univerzální třída Route, ale pro specifitější routování se občas vyplatí napsat si třídu vlastní. Mám tedy třídu 'MyRouter implements IRoute' a je vystaráno... Zrovna Nette ti takto na spoustě místech nic nenutí - pokud potřebuješ, můžeš si napsat implementaci vlastní.

Lamicz:

RoW: Kdyz trida implenmetuje interface, lze se na nej dotazat pres operator instanceof:

<?php

interface ITest
{
}

class
Test implements ITest
{
}

$o = new Test;
if(
$o instanceof ITest){
// true
}

?>

Ja je taky nepouzivam, ale bylo mi receno, ze je to vyjadreni toho, co ta trida "umi". Podle implementovanych metod mame hned jasno, ale nezajima nas konkretni realizace pro danou tridu. Pouziva se hlavne u rozsahlejsich projektu. Chytrejsi to urcite upresni ;)

finc:

Kontrola instanceof jen zjistuje, zda je objekt daneho typu. Pouziti pro interface neni uplne na miste.

Jinak interface je zaklad pri tvorbe objektove orientovaneho kodu. Pouziti interface je primo obsazene v jedne ze zakladnich pravidel: "Programovat vuci rozhrani."

Spravne navrzeny OO kod by mel znat pojmy jako:  zapouzdrenost (odstineni od implementace), znovupouzitelnost. Toho bez interface dosahnete velice tezko.

Jazyky se striktne typovou kontrolou Vas nuti veci jako interface pouzivat. U dynamicky typovanych jazyku (jako PHP) je to spise vlastni peclivost.

Jinak ukazky vyuziti interface jsou primo v navrovych vzorech, viz napriklad: http://cs.wikipedia.org/wiki/Composite

finc:

Samozrejme pod pojmem zapouzdrenost nejde jen o odstineni od implementace, ale take o to, abych nechal k dispozici jen to, co je skutecne nutne a na co je moje API schopne reagovat.

Lamicz:

Jinak bych mel jeste dotaz na Jakuba, proc misto "public" pises "var". Ze vynechavas "public" u function se da pochopit, ale "var" mi pripada spise jak PHP4 styl a je to IMHO mene prehledne. Kod stejne pod PHP4 nepojede. Mozna jsem natvrdly ;)

ikona Jakub Vrána OpenID:

Mám to tak navyklé z Adminera, který je kompatibilní i s PHP 4. Ale lepší je opravdu public hlavně proto, že v některé verzi PHP bylo var označeno za zastaralé (a později zase odznačeno).

Diskuse je zrušena z důvodu spamu.

avatar © 2005-2024 Jakub Vrána. Publikované texty můžete přetiskovat pouze se svolením autora. Ukázky kódu smíte používat s uvedením autora a URL tohoto webu bez dalších omezení Creative Commons. Můžeme si tykat. Skripty předpokládají nastavení: magic_quotes_gpc=Off, magic_quotes_runtime=Off, error_reporting=E_ALL & ~E_NOTICE a očekávají předchozí zavolání mysql_set_charset. Skripty by měly být funkční v PHP >= 4.3 a PHP >= 5.0.