Přejít k navigační liště

Zdroják » Různé » Prezentační vzory z rodiny MVC

Prezentační vzory z rodiny MVC

Články Různé

Obecné vztahy v architektuře MVC byly obsahem prvního dílu, v dnešním pokračování se podíváme na několik konkrétních vzorů z rodiny MVC. Velkého vstupu na scénu se dočká především vzor MVP, u kterého si ukážeme, v čem se liší od klasického MVC. Podíváme se rovněž na některá specifika webového MVC.

Nálepky:

Po přečtení prvního dílu máte dobrou představu o obecné architektuře MVC, ale jak už jsem zmínil, vedle obecných principů jsou pro reálný vývoj užitečné především jednotlivé variace MVC. Těm je věnováno dnešní pokračování.

Dva velcí kamarádi: MVC a MVP

Ačkoliv vás rozhodně nechci nudit historickými daty a přepisovat něco, co si můžete najít na webu, z praktického hlediska je užitečné podívat se na historický vývoj MVC, protože má zajímavou návaznost na současnost.

První návrh MVC pochází ze 70. let minulého století, kdy sálové počítače ještě uměly uvařit kávu (údajně přiblížením hrnku drženého v azbestové rukavici na vzdálenost 10 cm od výkonné jednotky). V oněch archaických dobách byly vstup a výstup na sobě do značné míry nezávislé – pro jednoduchost si můžete představit, že jeden blok kódu se staral o vykreslení obdélníčků na obrazovku, zatímco jiný zpracovával vstup z klávesnice, horké to novinky tehdejšího světa hardwaru (slovo „myš“ tehdy v počítačových sálech vyvolávalo spíše paniku než cokoliv jiného). Za dané situace není divu, že vznikl vzor MVC, protože v podstatě odrážel stav hardwaru své doby – View vykreslovalo uživatelské rozhraní a Controller zpracovával vstup.

Jak se ale operační systémy a programovací jazyky vyvíjely, input a output se postupně spojily do jednoho (například Button dnes zvládá jak své vykreslení na obrazovku, tak ošetřování událostí myši, klávesnice a dalších zařízení). Tím v podstatě zanikla původní potřeba pro MVC, protože „C“ už nemusel ošetřovat vstup. Také zde se ale postupně přišlo na to, že oddělení aplikačního kódu od definice uživatelského rozhraní je žádoucí, ačkoliv už komponenty teoreticky mohou vstup ošetřovat samy. Právě zde vzniká velký bratr MVC: architektonický vzor MVP (Model-View-Presenter). Od MVC se na obrázku liší jen málo, ale principiálně dost podstatně, jak uvidíme za chvíli.

Tím ale historie nekončí. V devadesátých letech na scénu vstupuje web, a světe div se, opět tu máme platformu, která neumí pořádně sloučit vstup a výstup (výstup je HTML, vstup je URL). Asi vás nyní nepřekvapím, když řeknu, že schéma fungování dnešních webových MVC frameworků je v zásadě stejné jako původní MVC ve Smalltalku.

Myslíte, že tady už končíme? Nikoliv… Kolem přelomu tisíciletí se objevuje technologie ASP.NET, která, ač webová, přišla s konceptem ovládacích prvků, které si napříč HTTP requesty udržují stav a umí reagovat na události podobně jako desktopové platformy. Zde opět MVC ztrácí smysl, protože vstup je ošetřen rovnou ve View, ale zcela podle očekávání lze pro ASP.NET Web Forms použít vzor MVP.

Vidíte tu zákonitost?

  • platforma s odděleným vstupem a výstupem: aplikovatelný je vzor MVC, kde „C“ zpracovává vstup
  • platforma s konceptem ovládacích prvků: aplikovatelný je vzor MVP, kde vstup zpracovává View a úloha Presenteru se mění

Protože je dnes jedinou široce rozšířenou „platformou s odděleným vstupem a výstupem“ web, MVC najdete především tam. Naopak vzhledem k tomu, že dnešní klientské technologie jsou prakticky všechny „widgetové“, nemá v nich klasické MVC příliš uplatnění a typicky se použije MVP.

Aby nebylo zmatení málo, s Controllerem se můžete setkat i v aplikacích widgetového typu. Tam však nemá na starost zpracování uživatelského vstupu, ale typicky se zabývá instrukcemi vyšší úrovně. Controller například může zachytávat události, které k němu „probublají“, a může je mapovat na nějakou funkcionalitu (ta může být zapouzdřena například do objektů implementujících vzor Command). Controlleru v tomto pojetí se někdy říká Application Controller a jeho přítomnost se nevylučuje s přítomností Presenterů.

Pojďme se nyní na jednotlivé vzory podívat.

Vzor MVC

Schéma vzoru MVC

Schéma je v podstatě grafickým shrnutím všeho, co byste už nyní měli vědět. Tok událostí v aplikaci vypadá následovně:

  1. Uživatel vykoná nějakou akci na uživatelském rozhraní
  2. Ta je zachycena Controllerem
  3. Controller rozhodne, jak na akci zareagovat, a typicky změní nějaké hodnoty v Modelu nebo přímo ovlivní View
  4. View zobrazí změny uživateli

Tento koloběh se potom opakuje. Na schématu ještě vidíte, že Controller obsahuje vazbu na View, což je v MVC frameworcích docela typické, ale tato vazba je méně důležitá než schopnost Controlleru upravit Model. Vztah Controlleru a View je obvykle takový, že Controller rozhoduje, které View zobrazit, nic moc navíc.

(Poznámka: pokud čirou náhodou budete studovat i úplně první implementaci MVC ve Smalltalku, možná vás zarazí, že View tehdy mělo přímou vazbu na Controller. Tehdy to byl ale implementační detail, ne způsob, jakým by View posílalo Controlleru jakékoliv zprávy.)

MVC v prostředí webu

Jak bylo řečeno, s MVC se dnes nejčastěji setkáte ve webových technologiích. Protože ale téměř všechny prezentační vzory původně vzešly z desktopových technologií, je u webového MVC potřeba některé drobnosti dovysvětlit, případně upravit.

Úplně na začátku musím upozornit na to, že klasická webová aplikace se z pohledu třívrstvého modelu výrazně liší od plně AJAXové aplikace typu GMail. Zatímco klasická aplikace bere prohlížeč pouze jako tupé zobrazovací zařízení a veškeré uživatelské rozhraní (HTML) generuje na serveru, plně AJAXová aplikace naopak spoléhá na přítomnost JavaScriptu a podstatná část prezentační logiky se přesouvá na klienta. Jak asi sami cítíte, mezi prezentační vrstvou realizovanou na serveru a na klientovi je dramatický rozdíl – serverové MVC proto bude potřebovat technologii jako např. Zend Framework nebo ASP.NET MVC, klientské MVC naproti tomu bude realizováno v JavaScriptu. V dnešní době se navíc často potkáte se třetí skupinou aplikací, která AJAX drobně používá, ale pouze jím doplňuje jinak klasický model. Zde je prezentační vrstva realizována jak na serveru, tak částečně na klientovi a MVC by tedy teoreticky šlo použít na obou stranách.

Slušný zmatek, že? V praxi naštěstí narazíte s drtivou většinou na aplikace, kterým stačí serverové MVC. Plně AJAXových aplikací je minimum a částečně AJAXové aplikace zase neobsahují v JavaScriptu tak komplikovanou logiku, aby se MVC vyplatilo použít. Na následujících řádcích proto „webovým MVC“ budu myslet serverovou implementaci.

Jak tedy v prostředí webu vypadají komponenty M, V a C?

Model je v tomto případě nejjednodušší část, protože je identický s Modelem v desktopových technologiích. (Obsahuje data a business logiku, s konkrétní prezentací nemá nic společného.)

View se někdy říká, že u webové aplikace je to HTML, ale to je jako říci, že u desktopové aplikace se View rovná pixelům na obrazovce, respektive nízkoúrovňovým vykreslovacím instrukcím. View je ve skutečnosti serverový kód, který se o generování HTML stará, tj. PHP, C#, Java, Ruby a podobně. Navíc ani u webové aplikace není nutné, aby bylo výstupem HTML – klidně to mohou být formáty jako XML nebo JSON.

Controller se v prostředí webu nejčastěji skládá ze dvou hlavních částí. První je tzv. Front Controller, který zachytává všechny HTTP požadavky, ty následně zpracuje a přepošle konkrétním Controllerům, což je ona druhá část. Konkrétní Controller potom typicky přijme data původně pocházející z HTTP požadavku, uloží je do Modelu a ten prováže s konkrétním View, které už se umí o vyrenderování HTML nebo jiného formátu postarat.

Všimněte si, že ačkoliv slovní popis ukazuje některá specifika webového MVC, schéma uvedené výše pořád platí. Principiální podobnost s původním MVC je prostě velká.

Vzor MVP a jeho variace

Nyní se dostáváme do světa widgetových systémů, ale to nutně neznamená, že opouštíme prostředí webu. Jak ASP.NET Web Forms, tak řada nových RIA technologií (Flex, Silverlight, JavaFX) mají společné to, že jsou jako stvořené pro MVP (Model-View-Presenter).

Začněme schématem:

Schéma vzoru MVP

Oproti MVC se toho změnilo poměrně hodně:

  • Uživatelský vstup i výstup nyní plně kontroluje View (skrze ovládací prvky uživatelského rozhraní jako Button nebo TextInput).
  • Primární motivací pro oddělení View a Presenteru už není nutnost ošetření vstupu, důvody jsou čistě architektonické (prezentační vrstva s MVP se udržuje lépe než monolitické View).
  • View má typicky přímou vazbu na Presenter. Většinou to není technicky nutné, ale řada lidí tuto realizaci preferuje a i většina literatury o MVP s přímou vazbou View na Presenter počítá.
  • Presenter v mnoha případech přímo pracuje s View, takže i tato vazba je silnější než v případě vzoru MVC.

Vidíte, že změn je celkem dost (nenechte si namluvit, že MVC a MVP se liší jen posledním písmenkem), proto znovu popíšu zodpovědnosti jednotlivých komponent:

  • Model je to samé, co dřív, tedy data plus business logika.
  • View navíc oproti MVC zpracovává uživatelský vstup. Typicky dělá pouze to, že např. v reakci na kliknutí myši zavolá nějakou metodu na Presenteru – pouze deleguje uživatelské akce. Jakákoliv aplikační logika ve View je chybou.
  • Presenter obsahuje aplikační a prezentační logiku. Manipuluje s Modelem, což pomocí systému notifikací zajistí aktualizaci View, nebo ovlivňuje View přímo.

Podle toho, jak velkou zodpovědnost View má, rozdělil Martin Fowler vzor MVP dále na dvě hlavní variace: Supervising Controller a Passive View.

Vzor Supervising Controller

Supervising Controller v podstatě přesně odpovídá původnímu MVP vzoru tak, jak byl popsán výše a jak vypadala původní implementace tzv. Dolphin Smalltalk MVP vzoru.

Neptejte se mě, proč Fowler v názvu použil slovo Controller, ačkoliv se zcela jasně jedná o Presenter a sám ve své eseji Supervising Controller řadí pod MVP vzory. Podle této webové stránky na Fowlerově webu (všimněte si názvu HTML souboru!) to vypadá, že Fowler zpočátku nebyl o vhodném označení rozhodnut, a tak si vybral, co mu zrovna přišlo lepší. Kniha, kde měl být tento vzor vydán, nakonec nebyla dokončena a název Supervising Controller se tak bohužel uchytil. (Poučení pro vás: až budete slavní, nepublikujte koncepty svých prací veřejně…)

Nyní ale zpět ke vzoru samotnému. Vrstvě View je svěřena zodpovědnost za zobrazení dat z modelu, nejčastěji pomocí vzoru Observer nebo v modernějších technologiích pomocí data bindingu. Jakákoliv složitější prezentační logika je potom přesunuta do Presenteru, který má dovoleno s View libovolně manipulovat.

Vzor Passive View

Motivací pro vzor Passive View je udělat View co „nejhloupější“, tj. ani jednoduché zobrazení dat z modelu není považováno za něco, co by mohlo být View svěřeno. Struktura aplikace vypadá takto:

Schéma vzoru Passive View

Jediným, zato však podstatným rozdílem je, že zmizela vazba View na Model. Presenter má nyní daleko větší zodpovědnost, protože kromě prezentační logiky musí i správě synchronizovat View s Modelem.

Primární motivací pro tento vzor jsou automatické testy, které se pro View píší velmi těžko. Veškerá logika se proto přesouvá do Presenteru, který lze pokrýt testy výrazně snadněji.

Pokračování příště

Jak jste měli možnost vidět, vzory z rodiny MVC/MVP se často liší ve zdánlivých detailech, ale každý se hodí do jiné situace. Příště se podíváme na některé alternativní vzory a celou problematiku uzavřeme.

Používáte MVP?

Komentáře

Subscribe
Upozornit na
guest
26 Komentářů
Nejstarší
Nejnovější Most Voted
Inline Feedbacks
View all comments
smilelover

Jak se u web apps realizuje ta sipka mezi V a M v prvnim nakresu MVP…? Akce z V je vzdy HTTP pozadavek a ten prece nikdy nezpracovava primo model.

Srigi

Dakujem za velmi dobry clanok. Skoda, ze serial nabuduce konci, osobne by som velmi privital, keby autor podrobne rozobral aspon najznamejsie PHP frameworky (Zend, Symfony, Nette).

babca

Taktez bych se primlouval za nejakou ukazku :). Jinak velice hezke clanky :)

Petr

Pěkný seriál, připojuji se s pochvalou.

ZuseX4

Konečně mi do celé problematiky někdo vnesl trochu pořádku :). Seriál o praktické implementaci by mohl být hodně užitečný a mohl by mnohem konkrétněji popsat o co se jedná. Určitě do toho!

v6ak

Pasivní view má tu nevýhodu, že není tolik univerzální. Mohl by nastat problém při pokusu použít více view s jedním Presenterem.

v6ak

Člověku pod přezdívkou se tyká…
Jinak narazil jsem na to v seriálu o Nette, kde se pasivní Views používají – vizte můj komentář: http://zdrojak.root.cz/clanky/nette-framework-refactoring/nazory/3551/vlakno/#o3567

Milan Čermák

Abych k textu přidal další zmatek, doplním, že model MVC a widgety se vzájemně nevylučují. V jazyku Smalltalk najdete obojí a widgety jsou zde implementovány právě pomocí modelu MVC. To umožňuje například přizpůsobit vzhled celé aplikace systému, na kterém běží, aniž by se musel změnit jediný řádek kódu.
MVC totiž od začátku nebyl jen systém jak psát aplikace s GUI, ale kompletní architektura grafického rozhraní do posledního tlačítka a textu. Tvůrce grafické aplikace dokonce nemusí mít ani ponětí o nějakém MVC, protože vše, co musí udělat, je definovat modely.

David Grudl

Upřímně řečeno, když jsem si četl návrh MVC z roku 1979 (http://heim.ifi.uio.no/~trygver/2007/MVC_Originals.pdf), tak mě překvapilo, jak hodně je "widgetové". O první implementaci z roku (tuším 1980?) ani nemluvě.

YF

dovedes si predstavit ze bys mel postavit dum? :) pokud bys to delal podobnym zbusobem jako premyslis o architekture v sw tak by me docela zajimalo jak by nakonec vypadal :))

jiravanet

YF: já si dovedu představit spoustu domů. Možná právě z toho důvodu by mě zajímalo, jak vypadá dům ve tvém podání, můžeš nám jej představit, rád se nechám poučit od někoho znalejšího. Takový ideální dům i s průběhem výstavby určitě nebude zajímat jen mě a budu rád za jiný pohled na, jak se zmiňuješ, architekturu, než která je prezentována v tomto seriálu. Díky (především za čas, který tomu věnuješ)
— J.

YF

promin ale jen kratce – kez bych na tohle mel energii … (tak bych ji asi pouzil stejne na neco jinyho) :) nicmene muzu Te ujistit ze podobne domy hruzy za ktere se evidentne autor stavi a rad by jimy zaplnil cele ulice a ktere jsou dnes tak moderni (viz. polobuh Fowler) – me desi a proto moje reakce; na znalejsiho bych si tu opravdu nechtel hrat – jde tu pouze o akci a reakci

Aleš Roubíček

"Já bych si dovolil reagovat" … Jiří Paroubek

Ano, shazovat něčí práci a nepředvést nic lepšího, je dovednost hodná velikého respektu.

YF

mno – nevim co je za praci prevykladat prevykladane po nekolikate uplne jinak a znova a jeste hur ale budiz – co se tyce kritiky – pokud napisu nekam neco – nemuzu se divit ze na to budou ostatni reagovat :) tim bych to ukoncil

jechtom

Takové příspěvky bych rovnou mazal, kritika bez sebemenší argumentace není nic jiného něž urážka. A urážka pod rouškou internetové anonymity je dost ubohá (obecně ji zvládají i 14ti letí kluci co si tak léčí komplexy).

YF

a co bys jeste vsechno udelal? :)

Martin Hassman

Děkuji všem za příspěvky, ale myslím, že se tohle vlákno dostalo již zcela mimo, čtenáře to nezajímá a já je proto ruším. Kontakt na autora článku je veřejný, v osobní diskusi můžete pokračovat soukromě.

Jaroslav Tulach

Díky za velmi pěkné články. Měl by je číst úplně každý! Dovolil jsem si je částečně přeložit (či spíše volně na ně odkázat) do angličtiny. Na původní zdroj jsem přidal odkaz, tak doufám, že to nevadí.

Martin Malý

Vzhledem k tomu, že články nejsou publikovány pod CC, tak je samosebou na místě vyžádat si souhlas autora. Uvedení odkazu na zdroj by rovněž mělo být výraznější než pouhý link, ideálně v podobě „text vychází z článku na serveru Zdroják…“ A pokud jsou obrázky převzaté z našich článků, tak k nim uvést: „Source: Zdrojak.cz“ Pokud budou tyto předpoklady splněny, tak to redakci nevadí. :)

Jaroslav Tulach

Upravil jsem svůj text, aby byly odkazy na zdrojak.root.cz nepřehlédnutelné. Děkuji redakci i autorovi za povolení.

Enum a statická analýza kódu

Mám jednu univerzální radu pro začínající programátorty. V učení sice neexistují rychlé zkratky, ovšem tuhle radu můžete snadno začít používat a zrychlit tak tempo učení. Tou tajemnou ingrediencí je statická analýza kódu. Ukážeme si to na příkladu enum.