mvc opis. Prikladan pristup web razvoju: MVC model

Dobar dan, drage kolege. U ovom članku želio bih govoriti o svom analitičkom razumijevanju razlika između MVC, MVP i MVVM uzoraka. Na pisanje ovog članka potaknula me želja za razumijevanjem modernih pristupa razvoju velikog softvera i odgovarajućih arhitektonskih značajki. U trenutnoj fazi moje karijere nisam izravni programer, tako da članak može sadržavati pogreške, netočnosti i nesporazume. Zanima vas kako analitičari vide što programeri i arhitekti rade? Onda dobrodošli pod kat.

Linkovi Prvo s čime bih želio započeti su linkovi na vanjske materijale kojima sam se rukovodio u procesu pisanja ovog članka:
Uvod U vrijeme kad je sunce jače sjalo i trava bila zelenija, tada je tim studenata, poput autora ovog članka, razvijao softver upisujući stotine redaka koda izravno u sučelje proizvoda. Ponekad su se za rad s podacima koristili servisi i upravitelji, a tada se rješenje dobivalo pomoću obrasca Document-View. Podrška ovakvog koda zahtijevala je enormne troškove, budući da je novog programera trebalo obučiti (kazati) koji je kod za što u proizvodu odgovoran, a ni o kakvom jediničnom testiranju nije bilo govora. Razvojni tim čine 4 osobe koje sjede u istoj prostoriji.
Vrijeme je prolazilo, poslovi su se mijenjali. Aplikacije koje su se razvijale postale su veće i složenije, od jednog kohezivnog razvojnog tima do mnogo različitih timova programera, arhitekata, stručnjaka za upotrebljivost, dizajnera i menadžera. Sada je svatko odgovoran za svoje područje: GUI, poslovna logika, komponente. Postojao je odjel za analizu, ispitivanje, arhitekturu. Trošak razvoja softvera porastao je stotine, pa čak i tisuće puta. Ovakav pristup razvoju zahtijeva stabilnu arhitekturu koja bi međusobno sinkronizirala različita funkcionalna područja proizvoda Uzorci S obzirom na cilj smanjenja troškova rada za razvoj složenog softvera, pretpostavimo da je potrebno koristiti gotova unificirana rješenja. Uostalom, uzorak radnji olakšava komunikaciju među programerima, omogućuje vam da se pozivate na dobro poznate konstrukcije i smanjuje broj pogrešaka.
Prema Wikipediji, uzorak (engleski design pattern) je ponovljivi arhitektonski dizajn, koji je rješenje dizajnerskog problema unutar nekog konteksta koji se često pojavljuje.

Počnimo s prvim glavnim – Model-View-Controller. MVC je temeljni obrazac koji je pronašao primjenu u mnogim tehnologijama, iznjedrio nove tehnologije i olakšava život programerima svaki dan.

MVC uzorak se prvi put pojavio u jeziku SmallTalk. Programeri su morali osmisliti arhitektonsko rješenje koje bi odvojilo grafičko sučelje od poslovne logike, a poslovnu logiku od podataka. Tako se u klasičnoj verziji MVC sastoji od tri dijela, po čemu je i dobio ime. Razmotrite ih:

Model Model se obično shvaća kao dio koji sadrži funkcionalnu poslovnu logiku aplikacije. Model mora biti potpuno neovisan o ostatku proizvoda. Sloj modela ne mora znati ništa o elementima dizajna i načinu na koji će biti prikazan. Postiže se rezultat koji vam omogućuje da promijenite prezentaciju podataka, kako se prikazuju, bez diranja samog modela.

Model ima sljedeće karakteristike:

  • Model je poslovna logika aplikacije;
  • Model ima znanje o sebi i ne zna za kontrolere i poglede;
  • Za neke projekte, model je samo sloj podataka (DAO, baza podataka, XML datoteka);
  • Za druge projekte, model je upravitelj baze podataka, zbirka objekata ili jednostavno logika aplikacije;
Pogled Pogled je odgovoran za prikaz podataka primljenih od modela. Međutim, pogled ne može izravno utjecati na model. Za pogled se može reći da ima pristup podacima samo za čitanje.

Pogled ima sljedeće značajke:

  • Pogled implementira prikaz podataka koji su na bilo koji način dobiveni iz modela;
  • U nekim slučajevima pogled može imati kod koji implementira neku poslovnu logiku.
Primjeri prezentacija: HTML stranica, WPF obrazac, Windows obrazac Razlike između MVC & MVVM & MVP Najčešći tipovi MVC uzorka su:
  • Model-View-Controller
  • Model-Pogled-Prezenter
  • Model-View-View Model

Razmotrite i usporedite svaki od njih.

Model-Pogled-Prezenter

Ovaj pristup vam omogućuje stvaranje apstrakcije pogleda. Da biste to učinili, morate istaknuti sučelje pogleda s određenim skupom svojstava i metoda. Prezenter zauzvrat prima referencu za implementaciju sučelja, pretplaćuje se za pregled događaja i mijenja model na zahtjev.

Značajke prezentera:

  • Pogled izravno komunicira s prezenterom pozivanjem odgovarajućih funkcija ili događaja na instanci prezentera;
  • Presenter komunicira s Viewom pomoću posebnog sučelja koje implementira View;
  • Jedna instanca izlagača povezana je s jednim pogledom.

Implementacija:
Svaki pogled mora implementirati odgovarajuće sučelje. Sučelje prikaza definira skup funkcija i događaja potrebnih za interakciju korisnika (na primjer, IView .ShowErrorMessage(string msg)). Prezenter mora imati referencu na implementaciju odgovarajućeg sučelja, koja se obično prosljeđuje u konstruktoru.
Logika prezentacije mora imati referencu na instancu izlagača. Svi događaji pogleda prosljeđuju se izlagaču na obradu i gotovo nikada njima ne upravlja logika pogleda (uključujući stvaranje drugih pogleda).

Primjer upotrebe: Windows Forms.

Model-View-View Model

Ovaj vam pristup omogućuje povezivanje elemenata pogleda sa svojstvima i događajima modela Pogled. Može se tvrditi da svaki sloj ovog uzorka nije svjestan postojanja drugog sloja.

Značajke modela View:

  • Dvosmjerna komunikacija uz prezentaciju;
  • Model pogleda je apstrakcija pogleda. Obično znači da su svojstva pogleda ista kao svojstva pogleda/modela
  • Model prikaza nema referencu na sučelje pogleda (IView). Promjenom stanja modela View automatski se mijenja pogled i obrnuto, jer se koristi mehanizam vezanja podataka (Bindings).
  • Jedna instanca modela pogleda povezana je s jednim zaslonom.

Implementacija:
Kada koristite ovaj uzorak, pogled ne implementira odgovarajuće sučelje (IView).
Pogled mora imati poveznicu na izvor podataka (DataContex), što je u ovom slučaju View model. Elementi pogleda vezani su (Bind) na odgovarajuća svojstva i događaje modela pogleda.
Zauzvrat, model View implementira posebno sučelje koje se koristi za automatsko ažuriranje elemenata prikaza. Primjer takvog sučelja u WPF-u bio bi INotifyPropertyChanged.

Primjer upotrebe: WPF

Model-View-Controller
Glavna ideja ovog uzorka je da i kontroler i pogled ovise o modelu, ali model ni na koji način ne ovisi o ove dvije komponente.

Značajke kontrolera

  • Kontroler određuje koji pogled treba prikazati u tom trenutku;
  • Događaji prikaza mogu utjecati samo na kontroler. Kontroler može utjecati na model i definirati drugačiji prikaz.
  • Moguće je imati više pogleda za samo jedan kontroler;

Implementacija:
Kontroler izvana presreće događaj i, u skladu s logikom ugrađenom u njega, reagira na taj događaj promjenom Modela pozivanjem odgovarajuće metode. Nakon promjene, Model koristi događaj koji je promijenio, a svi View događaji pretplaćeni na ovaj događaj, nakon što ga prime, obraćaju se Modelu za ažurirane podatke, nakon čega se prikazuju.

Slučaj upotrebe: MVC ASP.NET

Sažetak Implementacija MVVM i MVP obrazaca na prvi pogled izgleda prilično jednostavno i slično. Međutim, za MVVM, vezanje pogleda na View-model provodi se automatski, a za MVP je potrebno programirati
Čini se da MVC ima više opcija za upravljanje prikazom Opća pravila za odabir uzorka u MVVM-u
  • Koristi se u situaciji kada je vezanje podataka moguće bez potrebe za uvođenjem posebnih sučelja pogleda (tj. nema potrebe za implementacijom IView-a);
  • Čest primjer je WPF tehnologija.
MVP
  • Koristi se u situaciji kada povezivanje podataka nije moguće (ne možete koristiti Povezivanje);
  • Uobičajen primjer je korištenje Windows Forms.
MVC
  • Koristi se u situaciji kada komunikacija između prikaza i drugih dijelova aplikacije nije moguća (i ne možete koristiti MVVM ili MVP);
  • Uobičajen slučaj upotrebe je ASP.NET MVC.
Zaključak U zaključku, autor ovog članka želi istaknuti da striktno pridržavanje samo jednog obrasca nije uvijek najbolji izbor. Na primjer, zamislite da želite koristiti MVVM za razvoj aplikacija koristeći Windows Forms kroz svojstvo Vezovi kontrola. Vaš cilj je odvojiti prezentaciju od poslovne logike i logike koja ih povezuje. Aplikacija bi trebala biti lako testirana i održavana, te razumljiva analitičarima (uostalom, postoji samo jedan točan odgovor na pitanje "u čemu se mjeri performansa tvrdog diska?" - u Joulesima (apstraktni primjer Model -> Pogledi) ).

Hvala vam puno na vašem vremenu, ugodno čitanje!

SRC:
O'Reill. ActionScript 3.0 obrasci dizajna.
Poglavlje 12


Što je obrazac Model-View-Controller?

Model-View-Controller (MVC) je složeni uzorak ili višestruki uzorci koji zajedno rade na implementaciji složenih aplikacija. Ovaj uzorak se najčešće koristi za kreiranje aplikacijskih sučelja, a kao što naziv govori, sastoji se od tri elementa:

Model(model)
Sadrži podatke o aplikaciji i logiku za upravljanje stanjem te aplikacije

Izvođenje(Pogled)
Implementira korisničko sučelje i stanje aplikacije, vidljivo na ekranu

Kontrolor(Kontroler)
Rukuje radnjama korisnika koje utječu na stanje aplikacije.

Snaga MVC uzorka dolazi izravno iz odvajanja ova tri elementa kako bi se izbjeglo preklapanje područja odgovornosti svakog od njih. Pogledajmo za što je svaki od elemenata odgovoran.

Model

Model je odgovoran za upravljanje stanjem aplikacije. Logika aplikacije u modelu predstavljena je s dva važna zadatka: model odgovara na zahtjeve za stanje aplikacije i izvodi radnje kao odgovor na zahtjev za promjenom stanja.

Izvođenje

Pogled je izgled aplikacije. Korisnik komunicira s aplikacijom kroz View. Aplikacija može sadržavati više pogleda, koji mogu biti i ulazni i izlazni mehanizam. Na primjer, u prijenosnom digitalnom playeru kao što je iPod, zaslon uređaja bio bi View. Gumbi igrača također se smatraju Pogledom. Zaslon prikazuje naslov i trajanje pjesme, omot albuma i druge stvari koje su povezane s trenutnim stanjem uređaja. Pogled ne mora biti vidljiv. U prijenosnom playeru, glazba koja se reproducira u slušalicama također je izvedba. Na primjer, pritisak na tipku može izazvati neki zvučni odgovor u obliku klika u slušalicama. Promjene glasnoće također se odražavaju na izlaznom audio kanalu. Zvučna povratna informacija povezana je sa stanjem aplikacije.

Kontrolor

Iako pojam kontroler implicitno podrazumijeva sučelje preko kojeg se kontrolira aplikacija, u MVC uzorku kontroler ne sadrži elemente korisničkog sučelja. Kao što je gore spomenuto, elementi korisničkog sučelja koji pružaju unos pripadaju komponenti View. Upravljač, s druge strane, određuje kako Views reagira na korisnički unos.

Recimo da naš digitalni player ima gumbe Glasnije I Miran u Pogledu. Glasnoća zvuka je varijabla stanja. Model će pratiti ovu varijablu kako bi promijenio vrijednost ove varijable u skladu s logikom aplikacije. Ako je vrijednost glasnoće zvuka stupnjevana od 0 do 10, kontroler će odrediti koliko će povećati ili smanjiti zvuk kada se jedan od ovih gumba pritisne jednom. Ponašanje može reći Modelu da poveća glasnoću za 0,5, ili za 0,1, ili bilo koju drugu vrijednost koja je programski navedena. U tom smislu, kontroleri su specifičnosti implementacije koje definiraju kako će aplikacija odgovoriti na korisnički unos.

Iako svaki element u MVC trijadi ima zasebno i jedinstveno područje odgovornosti, oni ne funkcioniraju izolirano. Zapravo, da bi se sačinio MVC obrazac, svaki element mora komunicirati s ostalima. Što to znači, razmotrit ćemo u nastavku.

Interakcija MVC elemenata

Svaki element u MVC uzorku komunicira s ostalima na vrlo specifične načine. Komunikacija se provodi nizom događaja koji se obično pokreću interakcijom korisnika s aplikacijom. Redoslijed događaja izgleda ovako:

  • Korisnik stupa u interakciju s elementom sučelja (na primjer, klikne na gumb u prikazu).
  • Pogled šalje događaj klika kontroleru da odluči kako postupiti s klikom.
  • Kontrolor mijenja model na temelju onoga što odluči o pritisnutom gumbu.
  • Model obavještava pogled da se stanje modela promijenilo.
  • Pogled čita informacije o stanju u modelu i mijenja se sam.
  • Ovo je vrlo jednostavan dijagram interakcije MVC elemenata. U nekim slučajevima, kontroler može jednostavno reći Viewu da se promijeni. Ovo je jedini slučaj u kojem promjene Pogleda postaju neophodne zbog akcije korisnika i ne zahtijevaju promjene Modela, već samo rezultiraju samo vizualnim promjenama. Na primjer, razmislite o tome kako korisnik odabire pjesmu na digitalnom playeru. Odabire pjesmu s popisa tipkama za pomicanje. Pogled treba reći kontroleru da su pritisnute tipke za pomicanje gore ili pomicanje prema dolje, ali kontroler ne mora obavijestiti model. Izravno govori Viewu da pomiče popis pjesama u željenom smjeru. Takva radnja korisnika ne zahtijeva izmjene Modela. Međutim, kada korisnik odabere pjesmu s popisa i počne je reproducirati, kontroler će promijeniti model kako bi odražavao tu promjenu u vrijednosti pjesme koja se trenutno reproducira.

    Osim toga, promjene u modelu nisu uvijek potaknute radnjama korisnika. Model se može ažurirati na temelju određenih događaja. Uzmimo, na primjer, indikator cijene dionica. Model nije povezan s trenutnom vrijednošću dionica. Međutim, sama cijena se mijenja i Model može postaviti mjerač vremena za primanje periodičnih ažuriranja s web usluge. A onda, svaki put kada Model ažurira svoje podatke o cijeni dionice, obavijestit će View da se stanje promijenilo.

    Još jedna značajka MVC obrasca je da svaki takav model može imati više od jednog pogleda pridruženog sebi. Na primjer, u našem prijenosnom playeru, postavke glasnoće mogu se prikazati na zaslonu pomoću mjerača razine. Osim toga, razina zvuka na audio izlazu korelira s glasnoćom zvuka u slušalicama. I zaslon i zvuk u slušalicama su prikazi statusa uređaja.

    Pogledajte sliku 12-1 i obratite pažnju na smjer strelica. Oni pokazuju tko inicira interakciju između elemenata. Da bi jedan MVC element mogao komunicirati s drugim, mora znati za njega i posjedovati referencu na taj element.

    Zamislite Model, View i Controller kao tri različite klase. Pogledajmo koje klase moraju imati reference na druge klase:

    Izvođenje
    Mora imati referencu i na Model i na Kontrolora

    Kontrolor
    Mora posjedovati referencu na Model

    Započeli smo izjavom da je MVC složeni uzorak koji kombinira više uzoraka. Sigurno se pitate koji su uzorci uključeni u ovaj složeni uzorak. Ili, točnije, kako ih se može prikazati? Glavna prednost korištenja MVC obrasca je mogućnost da se on raščlani na tri sastavna elementa. To nam omogućuje povezivanje više pogleda s istim modelom, zamjenu modela i kontrolera bez utjecaja na druge elemente. Ali neki elementi u MVC trijadi moraju održavati reference na druge elemente, te također podržavati aktivnu komunikaciju među njima. Kako možemo nazvati takvu podjelu? To ima veze s obrascima promatrača, strategije i kompozita.

    Ubacivanje uzoraka u MVC

    Kao što smo već vidjeli, model se može povezati s više pogleda. U MVC-u, model mora obavijestiti sve poglede povezane s njim o promjenama koje se događaju. Osim toga, to se mora učiniti bez poznavanja specifičnih pojedinosti o Pogledima, pa čak i bez znanja koliko se Pogleda treba promijeniti. Ovaj se zadatak najbolje postiže korištenjem implementacije uzorka preglednika (vidi Poglavlje 8).

    Svaki model može imati više prikaza povezanih s njim. Slično tome, Views može biti složen, s višestrukim prozorima ili panelima koji sadrže druge elemente korisničkog sučelja. Na primjer, takvi elementi sučelja kao što su gumbi, tekstualna polja, popisi, klizači itd. mogu se grupirati u panel s karticama, a panel, pak, može biti dio prozora zajedno s drugim panelima. Svaki gumb ili grupa gumba može biti Pogled. Isto je i sa zbirkom tekstualnih polja. Čini se korisnim postupati s pločom ili prozorom koji sadrži zbirke jednostavnih prikaza na isti način na koji postupamo s bilo kojim drugim prikazima. Ovo je mjesto gdje će nam korištenje uzorka povezivača uštedjeti mnogo truda (vidi Poglavlje 6). Zašto je implementacija uzorka povezivača toliko korisna u ovom kontekstu? Ako se pogledi mogu ugniježditi, što i jesu kada su stvoreni pomoću obrasca Composer, postupak ažuriranja je pojednostavljen. Događaj ažuriranja automatski će zaobići sve prikaze potomke. Stvaranje složenih prikaza postaje lakše kada nema potrebe za slanjem pojedinačnih poruka ažuriranja svakom ugniježđenom prikazu.

    Pogledi ograničavaju svoju aktivnost samo na vanjski prikaz stanja Modela. Oni prosljeđuju događaje korisničkog sučelja kontroleru. Stoga je kontroler više algoritam za rukovanje korisničkim unosom u određenom prikazu. Takvo delegiranje sažima implementaciju načina na koji se određeni element prilagođenog elementa ponaša u slučaju promjene u Modelu. Možemo vrlo lako zamijeniti jedan kontroler za isti pogled kako bismo dobili drugačije ponašanje. Ovo je idealan kontekst za implementaciju obrasca strategije.

    Primjer minimalističkog MVC uzorka

    Ovaj jednostavan primjer prati pritiske tipki. Kada se pritisne sljedeća tipka, to uzrokuje promjenu modela i obavještava View da se ažurira. Prikaz koristi Flashov standardni izlazni prozor za postavljanje znakovnog koda koji je korisnik upisao u njega. Šifra znaka je numerička vrijednost znaka u tablici kodova trenutnog izgleda. Ovaj primjer objašnjava kako su uzorci preglednika, strategije i graditelja integrirani u MVC.

    Model kao konkretan predmet u predlošku preglednika

    Odnos između modela i pogleda je odnos između predmeta i preglednika (vidi Poglavlje 8). Model mora implementirati sučelje Subject, koje je dio obrasca Browser. Srećom, ActionScript 3.0 ima ugrađene klase koje već implementiraju ovo načelo, koristeći ActionScript model događaja za obavještavanje preglednika o promjenama.

    Klasa EventDispatcher u ActionScriptu 3.0

    Klasa EventDispatcher opremljena je sučeljem IEventDispatcher. Zajedno s drugim metodama, sučelje IEventDispatcher definira sljedeće metode koje su potrebne za predmet u predlošku preglednika. (Pogledajte AS3 dokumentaciju za detalje o svim parametrima metode).

    addEventListener(tip:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false) :void removeEventListener(type:String, listener:Function, useCapture:Boolean = false) :void dispatchEvent( događaj:Događaj) :Booleov

    Kako bi model djelovao kao konkretni subjekt u uzorku preglednika, morate implementirati sučelje IEventDispatcher. Međutim, najlakši način da određena prilagođena klasa dobije mogućnost distribucije događaja je naslijeđivanje od klase EventDispatcher.

    Preglednik registrira metode slušatelja za primanje obavijesti od EventDispatcher objekata pomoću metode addEventListener().

    Model

    Naš model pohranjuje šifru znaka koja odgovara pritisnutoj tipki u svojstvu. Morate implementirati postavljač i dobivač kako biste omogućili View i Controlleru pristup i promjenu ovog svojstva. Definirajmo za naš model (primjer 12-1).

    Primjer 12-1. IModel.as

    paket ( import flash.events .* ; javno sučelje IModel proširuje IEventDispatcher ( funkcija setKey(key :uint) :void ; funkcija getKey() :uint; ) )

    Sučelje IModel, prikazano u primjeru 12-1, proširuje sučelje IEventDispatcher i definira nekoliko metoda za čitanje i postavljanje znakovnog koda posljednje pritisnute tipke. Budući da sučelje IModel proširuje IEventDispatcher, svaka klasa koja ga implementira mora implementirati sve metode definirane u oba sučelja. Klasa Model prikazana u primjeru 12-2 implementira sučelje IModel.

    Primjer 12-2. Model.kao

    package ( import flash.events .* ; javna klasa Model proširuje EventDispatcher implementira IModel ( private var lastKeyPressed:uint=0 ; javna funkcija setKey(key :uint) :void ( this .lastKeyPressed =key ; dispatchEvent(new Event(Event.CHANGE) ) ) ; // događaj propagira ) javna funkcija getKey() :uint ( return lastKeyPressed; ) ) )

    Klasa Model proširuje klasu EventDispatcher, koja već implementira sučelje IEventDispatcher. Imajte na umu da se funkcija dispatchEvent() poziva unutar metode setKey(). Šalje događaj CHANGE svim registriranim preglednicima čim se promijeni vrijednost lastKeyPressed unutar metode setKey().

    Kontrolor kao konkretna strategija u predlošku strategije.

    Odnos između kontrolera i pogleda može se predstaviti kao strategija i kontekst u obrascu strategije. Svaki kontroler bit će posebna strategija koja implementira traženo ponašanje unutar okvira sučelja strategije.

    Kontrolor

    U našem minimalističkom primjeru, ponašanje koje se zahtijeva od kontrolera je samo prihvaćanje događaja pritiska tipke. IKeyboardInputHandler je strateško sučelje (Primjer 12-3) gdje je definirana jedna metoda keyPressHandler().

    Primjer 12-3. IKeyboardInputHandler.as

    paket ( import flash.events .* ; javno sučelje IKeyboardInputHandler ( function keyPressHandler(event:KeyboardEvent) :void ; ) )

    Konkretni kontroler bila bi klasa kontrolera (primjer 12-4), koja implementira sučelje IKeyboardInputHandler.

    Primjer 12-4. Kontrolor.as

    paket ( import flash.events .* ; javna klasa Controller implementira IKeyboardInputHandler ( private var model:IModel; javna funkcija Controller(aModel:IModel) ( this .model =aModel; ) javna funkcija keyPressHandler(event:KeyboardEvent) :void ( model. setKey (event.charCode); // promjena modela ) ) )

    Imajte na umu da kontroler ima konstruktor koji uzima instancu modela kao parametar. Ovo je neophodno kako bi kontroler mogao komunicirati s modelom, kao što je prikazano na slici 12-1. Stoga je potrebno pohraniti referencu na Model.

    Metoda keyPressHandler() uzima događaj korisničkog sučelja (u ovom slučaju, KeyboardEvent) kao parametar i zatim odlučuje kako njime postupiti. U našem primjeru, jednostavno postavlja kod pritisnute tipke u modelu.

    Prikaz kao konkretni preglednik u predlošku preglednika i kontekst u predlošku strategije

    Pogled je možda najsloženiji element u MVC uzorku. On igra ulogu integrirajućeg dijela u implementaciji obrazaca preglednika i strategije, što čini temelj njegovog odnosa s modelom i kontrolerom. Klasa View prikazana u ispisu 12-5 implementira View u minimalističkom primjeru.

    Primjer 12-5. Pogled.kao

    paket ( import flash.events .* ; import flash.display .* ; public class View ( private var model:IModel; private var controller:IKeyboardInputHandler; public function View(aModel:IModel,oController:IKeyboardInputHandler,target :Stage) ( ovo .model =aModel; ovaj .controller =oController; // pretplaćuje se na primanje obavijesti od modela model.addEventListener (Event.CHANGE ,this .update ) ; // pretplaćuje se na primanje pritisaka tipki od ciljne scene .addEventListener (KeyboardEvent.KEY_DOWN, this .onKeyPress ) ; ) privatna funkcija update(event:Event) :void ( // dobivanje podataka iz modela i ažuriranje prikaza prikaza (model.getKey () ) ; ) privatna funkcija onKeyPress(event:KeyboardEvent) :void ( / / obrada se prosljeđuje kontroleru (strategija) za obradu controller.keyPressHandler (događaj) ; ) ) )

    Pogledu su potrebne i reference modela i kontrolera kako bi mogao s njima komunicirati, kao što je prikazano na slici 12-1. I instanca Modela i instanca Controllera prosljeđuju se Viewu u njegovom konstruktoru. Osim toga, View u našem primjeru treba referencu na Stage kako bi se registrirao kao primatelj događaja pritiska tipke.

    Osim crtanja korisničkog sučelja, klasa View obavlja još nekoliko važnih zadataka. Registrira se s modelom za primanje događaja ažuriranja i delegira kontroleru za rukovanje korisničkim unosom. U našem primjeru, Pogled nema vanjsku vidljivu prisutnost na sceni, ali prikazuje stanje modela u izlaznom prozoru. Treba primiti događaj pritiska tipke i registrirati metodu onKeyPress() da primi događaj KEY_DOWN sa scene. Drugi zadatak je registracija metode slušača update() za primanje događaja CHANGE iz modela. Kada se primi obavijest o promjeni, metoda update() čita kod zadnje pritisnute tipke iz modela i ispisuje ga u izlazni prozor pomoću funkcije trace().

    Izgradnja MVC trijade

    Razmotrili smo implementaciju svakog od tri dijela MVC uzorka zasebno. Međutim, mora postojati klijent koji će inicijalizirati svaki element i izgraditi MVC model. Zapravo, neće biti složene konstrukcije - sve što treba učiniti već je učinjeno prilikom pisanja klasa Model, View i Controller. Primjer 12-6 pruža klasu Flash dokumenta koja ilustrira elemente MVC-a.

    Primjer 12-6. Main.as (glavna klasa minimalističkog primjera)

    paket ( import flash.display .* ; import flash.events .* ; /** * Glavna klasa * @ svrha: klasa dokumenta za film */ javna klasa Main proširuje Sprite ( javna funkcija Main() ( var model:IModel=new Model ; var controller:IKeyboardInputHandler=new Controller(model) ; var view:View=new View(model,controller,this .stage) ; ) ) )

    Nakon što se model, kontroler i pogled inicijaliziraju, oni će međusobno komunicirati i početi raditi. Pritiskom na tipku na tipkovnici prikazat će se odgovarajući kod znaka u izlaznom prozoru.

    Morate onemogućiti prečace za testiranje pritisaka na tipke. U suprotnom će Flash korisničko sučelje presresti događaje pritiskanja tipki koje odgovaraju prečacima. Kako biste onemogućili tipkovničke prečace, odaberite Onemogući tipkovničke prečace iz izbornika Kontrola dok se videozapis prikazuje.

    Imajte na umu da se instanca modela prosljeđuje kontroleru. Slično, instance modela i kontrolera prosljeđuju se u prikaz. Možemo jednostavno zamijeniti postojeći model i kontroler s drugima, sve dok implementiraju sučelja IModel i IKeyboardInputHandler. Dodatni pogledi također se mogu bezbolno dodati izravno u odnos Subjekt-Gledatelj između modela i prikaza. Model ne zna ništa o Pogledima, budući da je na Pogledu da se registrira kao slušatelj za obavijesti o promjenama Modela. Ovo je veliki plus MVC uzorka; Model, View i Controller su odvojeni, labavo povezani, što daje fleksibilnost u njihovoj uporabi.

    Ugniježđeni prikazi i čvorovi predložaka

    Podsjetimo se da je Pogled možda najsloženiji element u MVC trijadi, jer je u MVC kontekstu uključen iu implementaciju obrasca preglednika i strategije. Naši View elementi mogu biti složeniji jer mogu implementirati treći obrazac, Layoutr (pogledajte primjere Layoutr uzorka u 6. poglavlju). Implementacija pogleda kao elemenata predloška Composite vam omogućuje da se nosite sa složenim korisničkim sučeljima koja sadrže više pogleda. Ugniježđeni pogledi donose neke prednosti procesu ažuriranja korisničkog sučelja jer se ažuriranja mogu širiti duž grana strukturalnog stabla kompozitnog pogleda. Composite Views također može dodavati i uklanjati ugniježđene Views na temelju ponašanja aplikacije i korisničkih postavki. Dobar primjer složenog sučelja je ploča Properties Inspector u Flash autorskom okruženju. Sadržaj Properties Inspectora osjetljiv je na kontekst, a elementi korisničkog sučelja pojavljuju se i nestaju ovisno o tome koji je objekt odabran u sceni.

    Komponentni i kompozitni prikaz

    Prvi korak je stvoriti komponente i složene klase za View. Ove klase moraju biti deklarirane kao apstraktne, moraju biti podklase i ne smiju se instancirati, kao što je prikazano u primjeru 12-7.

    Primjer 12-7. ComponentView.as

    paket ( import flash.errors .IllegalOperationError ; import flash.events .Event ; import flash.display .Sprite ; javna klasa ComponentView proširuje Sprite ( ( protected var model:Object ; protected var controller:Object ; javna funkcija ComponentView(aModel:Object, aController:Object =null ) ( this .model =aModel; this .controller =aController; ) javna funkcija add (c:ComponentView) :void ( throw new IllegalOperationError("operacija dodavanja nije podržana" ) ; ) javna funkcija remove(c: ComponentView) :void (baci novu IllegalOperationError("operacija uklanjanja nije podržana" ) ; ) javna funkcija getChild(n:int ) :ComponentView ( baci novu IllegalOperationError("operacija getChild nije podržana" ) ; vrati null ; ) // ABSTRAKTNA metoda( mora se nadjačati u klasi potomku) javna funkcija update(event:Event=null ) :void ( ) ) ) )

    Klasa ComponentView iz primjera 12-7 definira apstraktno sučelje za Component View. Ovo je slično klasičnoj klasi komponenti iz poglavlja 6, ali s nekoliko ključnih razlika. Klasa ComponentView sadrži referencu na model i pogled i sadrži konstruktor. Ne rukuju svi pogledi korisničkim unosom, a komponentni pogled može se konstruirati jednostavnim prosljeđivanjem instance modela. Stoga je parametar aController u konstruktoru prema zadanim postavkama null. Također imajte na umu da je klasa ComponentView izvedena iz klase Sprite. Ovo ima smisla budući da većina prikaza crta korisničko sučelje na pozornici. Možemo koristiti svojstva i metode implementirane u klasi Sprite za crtanje i dodavanje objekata na popis za prikaz.

    Metoda update() mora se ponašati kao apstraktna metoda. Podređeni pogledi koji su potomci ComponentViewa moraju nadjačati i implementirati metodu update() kako bi mogli ažurirati svoj dio korisničkog sučelja. Iz tog razloga, metodi se prosljeđuje parametar tipa Event. Ovaj je parametar također postavljen na null prema zadanim postavkama, što vam omogućuje pozivanje update() bez prosljeđivanja događaja kao parametra. Ovaj je pristup koristan kada je inicijalno prikazano korisničko sučelje u zadanom stanju, a naš sljedeći primjer to ilustrira.

    Klasa CompositeView proširuje ComponentView i nadjačava metode koje su odgovorne za podređene prikaze.

    Primjer 12-8. CompositeView.as

    package ( import flash.events .Event ; // ABSTRACT class (morate ga naslijediti bez stvaranja instance ove klase) public class CompositeView extends ComponentView ( private var aChildren:Array ; public function CompositeView(aModel:Object ,aController: Object =null ) ( super (aModel,aController) ; this .aChildren =new Array ; ) override public function add (c:ComponentView) :void ( aChildren.push (c) ; ) override public function update(event:Event=null ) :void ( za svaki (var c:ComponentView u aChildren) ( c.update (event) ; ) ) ) )

    Obratite pozornost na funkciju nadjačavanja update() klase CompositeView u primjeru 12-8. Poziva metodu ažuriranja na svim podređenim klasama. Stoga će pozivanje funkcije update() u korijenu strukture kompozitnog prikaza proširiti ažuriranje kroz strukturu i preći stablo komponente, ažurirajući sve poglede. Proširimo klase CompositeView i ComponentView i stvorimo strukturu View da vidimo kako funkcionira.

    Mnogi ljudi počinju pisati projekt da rade s jednim zadatkom, ne implicirajući da može prerasti u višekorisnički sustav upravljanja, recimo, sadržajem ili, ne daj Bože, produkcijom. I sve se čini super i cool, sve radi dok ne počnete shvaćati da se kod koji je napisan sastoji isključivo od štaka i tvrdog koda. Kod je pomiješan s izgledom, zahtjevima i štakama, ponekad čak i nečitljiv. Pojavljuje se hitan problem: kada dodajete nove značajke, morate se dugo petljati s ovim kodom, prisjećajući se "što je tamo napisano?" i proklinjite sebe u prošlosti.

    Možda ste čak čuli za uzorke dizajna i čak prelistali ove sjajne knjige:

    • E. Gamma, R. Helm, R. Johnson, J. Vlissides “Tehnike objektno orijentiranog dizajna. Dizajn uzorci";
    • M. Fowler "Arhitektura poslovnih softverskih aplikacija".
    I mnogi su, ne bojeći se golemih priručnika i dokumentacije, pokušali proučiti bilo koji od modernih okvira i, suočeni s teškoćama razumijevanja (zbog prisutnosti mnogih arhitektonskih koncepata međusobno vješto povezanih), odgodili proučavanje i primjenu moderni alati u drugom planu.

    Predstavljeni članak bit će koristan prvenstveno početnicima. U svakom slučaju, nadam se da ćete za nekoliko sati moći steći ideju o implementaciji MVC obrasca koji je u osnovi svih modernih web okvira, kao i dobiti “hranu” za daljnje razmišljanje o “ kako to učiniti". Na kraju članka nalazi se izbor korisnih poveznica koje će vam također pomoći da shvatite od čega se sastoje web okviri (osim MVC) i kako funkcioniraju.

    Očvrsli PHP programeri vjerojatno neće pronaći nešto novo za sebe u ovom članku, ali njihovi komentari i komentari na glavni tekst bili bi od velike pomoći! Jer bez teorije ne može praksa, a bez prakse je teorija beskorisna, onda će prvo biti malo teorije, a onda ćemo prijeći na praksu. Ako ste već upoznati s konceptom MVC-a, možete preskočiti teorijski dio i prijeći ravno na praksu.

    1. Teorija MVC uzorak opisuje jednostavan način za izgradnju strukture aplikacije koja ima za cilj odvojiti poslovnu logiku od korisničkog sučelja. Kao rezultat toga, aplikaciju je lakše skalirati, testirati, održavati i, naravno, implementirati.

    Razmotrite konceptualnu shemu MVC predloška (po mom mišljenju, ovo je najuspješnija shema od onih koje sam vidio):

    U MVC arhitekturi, model osigurava podatke i pravila poslovne logike, pogled je odgovoran za korisničko sučelje, a kontroler osigurava interakciju između modela i pogleda.

    Tipični tijek rada MVC aplikacije može se opisati na sljedeći način:

  • Kada korisnik uđe u web resurs, inicijalizacijska skripta stvara instancu aplikacije i pokreće je za izvršenje.
    Ovo prikazuje prikaz, recimo, glavne stranice web mjesta.
  • Aplikacija prima zahtjev od korisnika i određuje traženi kontroler i akciju. U slučaju glavne stranice izvodi se zadana radnja ( indeks).
  • Aplikacija instancira kontroler i pokreće akcijsku metodu,
    koji npr. sadrži pozive modelu koji čitaju informacije iz baze podataka.
  • Nakon toga, akcija generira pogled s podacima primljenim iz modela i prikazuje rezultat korisniku.
  • Model – sadrži poslovnu logiku aplikacije i uključuje metode za uzorkovanje (to mogu biti ORM metode), obradu (primjerice, validacijska pravila) i pružanje specifičnih podataka, što ih često čini vrlo gustim, što je sasvim normalno.
    Model ne bi trebao izravno komunicirati s korisnikom. Sve varijable koje se odnose na zahtjev korisnika moraju se obraditi u kontroleru.
    Model ne bi trebao generirati HTML ili drugi kod za renderiranje, koji se može mijenjati ovisno o potrebama korisnika. Takvim kodom treba rukovati u pogledima.
    Isti model npr.: model autentifikacije korisnika može se koristiti i u korisničkom i u administrativnom dijelu aplikacije. U ovom slučaju, možete premjestiti zajednički kod u zasebnu klasu i naslijediti od nje, definirajući metode specifične za podaplikacije u nasljednicima.

    Pogled - koristi se za postavljanje vanjskog prikaza podataka primljenih od kontrolera i modela.
    Pogledi sadrže HTML oznake i male umetke PHP koda za indeksiranje, oblikovanje i prikaz podataka.
    Ne bi trebao izravno pristupiti bazi podataka. Modeli bi to trebali raditi.
    Ne bi trebalo raditi s podacima primljenim na zahtjev korisnika. Ovaj zadatak mora izvršiti upravljač.
    Može izravno pristupiti svojstvima i metodama kontrolera ili modela kako bi dobio podatke spremne za izlaz.
    Pogledi se obično dijele na zajednički predložak koji sadrži oznake zajedničke za sve stranice (na primjer, zaglavlje i podnožje) i dijelove predloška koji se koriste za prikaz izlaznih podataka iz modela ili prikaz obrazaca za unos podataka.

    Kontroler je poveznica koja povezuje modele, prikaze i druge komponente u radnu aplikaciju. Kontrolor je odgovoran za obradu zahtjeva korisnika. Kontroler ne smije sadržavati SQL upite. Bolje ih je držati u modelima. Kontroler ne smije sadržavati HTML ili druge oznake. Zaslužuje da se iznese na vidjelo.
    U dobro dizajniranoj MVC aplikaciji, kontroleri su obično vrlo tanki i sadrže samo nekoliko desetaka redaka koda. Što se ne može reći o Stupid Fat Controllers (SFC) u CMS Joomla. Logika kontrolera prilično je tipična i većina je izdvojena u osnovnim klasama.
    Modeli su, s druge strane, vrlo debeli i sadrže većinu koda povezanog s obradom podataka. struktura podataka i poslovna logika koju sadrži obično su prilično specifični za određenu aplikaciju.

    1.1. Front Controller i Page Controller U većini slučajeva, interakcija korisnika s web aplikacijom odvija se putem poveznica. Pogledajte sada adresnu traku preglednika - ovaj ste tekst primili s ove veze. Ostale veze, poput onih na desnoj strani ove stranice, odvest će vas do drugog sadržaja. Dakle, poveznica predstavlja određenu naredbu web aplikaciji.

    Nadam se da ste već primijetili da različite stranice mogu imati potpuno različite formate za izradu adresne trake. Svaki format može predstavljati arhitekturu web aplikacije. Iako to nije uvijek slučaj, u većini slučajeva to je jasna činjenica.

    Razmotrite dvije opcije za adresnu traku, koje prikazuju neki tekst i korisnički profil.

    Približan kod obrade u ovom slučaju:
    switch($_GET["action"]) ( case "about" : require_once("about.php"); // prijelom stranice "O nama"; case "contacts" : require_once("contacts.php"); // prekid stranice "Kontakti"; case "feedback" : require_once("feedback.php"); // prekid stranice "Feedback"; zadano: require_once("page404.php"); // prekid stranice "404"; )
    Mislim da su to već učinili gotovo svi.

    Koristeći URL mehanizam za usmjeravanje, možete konfigurirati svoju aplikaciju da prihvaća zahtjeve poput ovog za prikaz istih informacija:
    http://www.example.com/contacts/feedback

    Ovdje su kontakti kontroler, a povratna informacija je metoda kontrolera kontakata koja prikazuje obrazac za povratne informacije, i tako dalje. Ovom pitanju ćemo se vratiti u praktičnom dijelu.

    Također je vrijedno znati da usmjerivači mnogih web okvira omogućuju stvaranje proizvoljnih URL ruta (navedite što svaki dio URL-a znači) i pravila za njihovu obradu.
    Sada imamo dovoljno teorijskog znanja da prijeđemo na praksu.

    2. Vježbajte Prvo, kreirajmo sljedeću strukturu datoteka i mapa:


    Gledajući unaprijed, reći ću da će osnovne klase Model, View i Controller biti pohranjene u osnovnoj mapi.
    Njihova djeca bit će pohranjena u direktorije kontrolera, modela i prikaza. Datoteka index.php je ulazna točka u aplikaciju. Datoteka bootstrap.php pokreće učitavanje aplikacije, uključujući sve potrebne module itd.

    Idemo redom; otvorite datoteku index.php i ispunite je sljedećim kodom:
    ini_set("pogreške_prikaza", 1); require_once "aplikacija/bootstrap.php";
    Ovdje ne bi trebalo biti pitanja.

    Zatim, skočimo ravno na datoteku bootstrap.php:
    require_once "core/model.php"; require_once "core/view.php"; require_once "core/controller.php"; require_once "core/route.php"; Ruta::start(); // pokretanje rutera
    Prva tri retka će sadržavati trenutno nepostojeće kernel datoteke. Posljednji redovi uključuju datoteku s klasom usmjerivača i pokreću je za izvođenje pozivanjem metode statičkog pokretanja.

    2.1. Implementacija URL usmjerivača Za sada, odstupimo od implementacije MVC uzorka i usredotočimo se na usmjeravanje. Prvi korak koji trebamo poduzeti je staviti sljedeći kod u .htaccess:
    RewriteEngine On RewriteCond %(REQUEST_FILENAME) !-f RewriteCond %(REQUEST_FILENAME) !-d RewriteRule .* index.php [L]
    Ovaj kod će preusmjeriti obradu svih stranica na index.php , što je ono što nam treba. Sjećate se da smo u prvom dijelu govorili o Front Controlleru?!

    Usmjeravanje ćemo smjestiti u zasebnu datoteku route.php u osnovnom direktoriju. U ovoj datoteci ćemo opisati klasu Route, koja će pokretati metode kontrolera, koji će zauzvrat generirati izgled stranica.

    Sadržaj datoteke Route.php

    klasa Ruta ( statička funkcija start() ( // zadani kontroler i akcija $controller_name = "Main"; $action_name = "index"; $routes = explode("/", $_SERVER["REQUEST_URI"]); // dobiti ime kontrolera if (!empty($routes)) ( $controller_name = $routes; ) // dobivanje naziva radnje if (!empty($routes)) ( $action_name = $routes; ) // dodavanje prefiksa $model_name = " Model_ ".$controller_name; $controller_name = "Controller_".$controller_name; $action_name = "action_".$action_name; // spojite datoteku s klasom modela (možda ne postoji datoteka modela) $model_file = strtolower($model_name ). ".php"; $model_path = "application/models/".$model_file; if(file_exists($model_path)) ( uključi "application/models/".$model_file; ) // spojite datoteku klase kontrolera $controller_file = strtolower ($controller_name).".php"; $controller_path = "application/controllers/".$controller_file; if(file_exists($controller_path)) ( uključi "aplikacija/controllers/".$controller_file; ) else ( /* bilo bi ispravno izbaciti iznimku ovdje, ali radi jednostavnosti odmah ćemo preusmjeriti na stranicu 404 */ Route::ErrorPage404(); ) // kreirati kontroler $controller = new $controller_name; $akcija = $akcija_name; if(method_exists($controller, $action)) ( // poziva radnju kontrolera $controller->$action(); ) else ( // također bi imalo više smisla izbaciti iznimku ovdje Route::ErrorPage404(); ) ) function ErrorPage404( ) ( $host = "http://".$_SERVER["HTTP_HOST"]."/"; header("HTTP/1.1 404 nije pronađen"); header("Status: 404 nije pronađen" ); zaglavlje(" Lokacija:".$host."404"); ) )


    Napominjem da klasa implementira vrlo pojednostavljenu logiku (unatoč voluminoznom kodu) i možda čak ima sigurnosnih problema. To je učinjeno namjerno, jer. pisanje punopravne klase usmjeravanja zaslužuje barem poseban članak. Pogledajmo glavne točke...

    Element globalnog polja $_SERVER["REQUEST_URI"] sadrži punu adresu na koju se korisnik prijavio.
    Na primjer: example.ru/contacts/feedback

    Korištenje funkcije eksplodirati adresa je podijeljena na komponente. Kao rezultat, dobivamo naziv kontrolera, za navedeni primjer, ovo je kontroler kontakti i naziv radnje, u našem slučaju - Povratne informacije.

    Zatim se povezuje datoteka modela (model može nedostajati) i datoteka kontrolera, ako postoji, i na kraju, kreira se instanca kontrolera i ponovno se poziva akcija ako je opisana u klasi kontrolera.

    Dakle, kada odete npr. na adresu:
    primjer.com/portfolio
    ili
    primjer.com/portfolio/index
    Usmjerivač će učiniti sljedeće:

  • spojite datoteku model_portfolio.php iz mape models koja sadrži klasu Model_Portfolio;
  • uključite datoteku controller_portfolio.php iz mape controllers koja sadrži klasu Controller_Portfolio;
  • će stvoriti instancu klase Controller_Portfolio i pozvati zadanu radnju - action_index opisanu u njoj.
  • Ako korisnik pokuša pristupiti adresi nepostojećeg kontrolera, na primjer:
    primjer.com/ufo
    tada će biti preusmjeren na stranicu 404:
    primjer.com/404
    Isto će se dogoditi ako korisnik pristupi radnji koja nije opisana u kontroleru.2.2. Povratak na implementaciju MVC-a. Idemo u mapu jezgre i dodamo još tri datoteke u datoteku route.php: model.php, view.php i controller.php


    Dopustite mi da vas podsjetim da će sadržavati osnovne klase, koje ćemo sada početi pisati.

    Sadržaj datoteke model.php
    model klase ( javna funkcija get_data() ( ) )
    Klasa modela sadrži jednu praznu metodu dohvaćanja podataka koja će biti nadjačana u klasama potomcima. Kada stvorimo klase potomke, sve će postati jasnije.

    Sadržaj datoteke view.php
    class View ( //public $template_view; // ovdje možete navesti zadani javni prikaz. function generate($content_view, $template_view, $data = null) ( /* if(is_array($data)) ( // pretvori niz elemente u varijable ekstrakt($data); ) */ uključi "application/views/".$template_view; ) )
    Nije teško pogoditi da metoda generirati dizajniran da oblikuje pogled. U njega se prosljeđuju sljedeći parametri:

  • $content_file - pregledi koji prikazuju sadržaj stranice;
  • $template_file - zajednički predložak za sve stranice;
  • $data je niz koji sadrži elemente sadržaja stranice. Obično se popunjava u modelu.
  • Funkcija uključivanja dinamički povezuje zajednički predložak (pogled), unutar kojeg će pogled biti ugrađen
    za prikaz sadržaja određene stranice.

    U našem slučaju, opći predložak sadržavat će zaglavlje, izbornik, bočnu traku i podnožje, a sadržaj stranica bit će sadržan u zasebnom obliku. Opet, ovo je učinjeno radi jednostavnosti.

    Sadržaj datoteke controller.php
    klasa Controller ( javni $model; javni $view; funkcija __construct() ( $this->view = new View(); ) funkcija action_index() ( ) )
    metoda indeks_radnje je radnja koja se poziva prema zadanim postavkama, nadjačat ćemo je pri implementaciji klasa potomaka.

    2.3. Implementacija klasa potomaka Modela i Kontrolora, stvaranje View-a Sada zabava počinje! Naša web-stranica posjetnica sastojat će se od sljedećih stranica:
  • Dom
  • Usluge
  • Portfelj
  • Kontakti
  • I također - stranica "404"
  • Svaka stranica ima vlastiti kontroler iz mape kontrolera i pogled iz mape pogleda. Neke stranice mogu koristiti model ili modele iz mape modela.


    Na prethodnoj slici, datoteka template_view.php je posebno označena - ovo je predložak koji sadrži oznake zajedničke za sve stranice. U najjednostavnijem slučaju to bi moglo izgledati ovako:
    Dom
    Kako bismo web stranici dali vidljiv izgled, napravit ćemo CSS predložak i integrirati ga u našu web stranicu mijenjajući strukturu HTML oznake i uključujući CSS i JavaScript datoteke:

    Na kraju članka, u odjeljku “Rezultat”, nalazi se poveznica na GitHub repozitorij s projektom u koji je napravljena integracija jednostavnog predloška.

    2.3.1. Stvaranje glavne stranice Počnimo s kontrolerom controller_main.php , ovdje je njegov kod:
    klasa Controller_Main proširuje Controller ( funkcija action_index() ( $this->view->generate("main_view.php", "template_view.php"); ) )
    Metoda generirati instanci klase View prosljeđuju se nazivi datoteka općeg predloška i pogleda sa sadržajem stranice.
    Osim radnje indeksa, kontroler naravno može sadržavati i druge akcije.

    Ranije smo razgovarali o datoteci s općim pogledom. Razmotrite datoteku sadržaja main_view.php:
    Dobrodošli!

    OLOLOSHA TEAM je tim prvoklasnih stručnjaka za razvoj web stranica s dugogodišnjim iskustvom u prikupljanju meksičkih maski, brončanih i kamenih statua iz Indije i Cejlona, ​​bareljefa i skulptura koje su izradili majstori Ekvatorijalne Afrike prije pet ili šest stoljeća. .


    Ovo sadrži jednostavno označavanje bez PHP poziva.
    Za prikaz glavne stranice možete koristiti jednu od sljedećih adresa:

    O primjeru korištenja pogleda koji prikazuje podatke primljene iz modela bit će riječi kasnije.

    2.3.2. Stvaranje stranice portfelja U našem slučaju, stranica portfelja je jedina stranica koja koristi model.
    Model obično uključuje metode dohvaćanja podataka, na primjer:
  • metode izvornih pgsql ili mysql knjižnica;
  • metode knjižnica koje provode apstrakciju podataka. Na primjer, metode biblioteke PEAR MDB2;
  • ORM metode;
  • metode za rad s NoSQL;
  • i tako dalje.
  • Radi jednostavnosti, ovdje nećemo koristiti SQL upite ili ORM izjave. Umjesto toga, simuliramo stvarne podatke i odmah vraćamo niz rezultata.
    Datoteka modela model_portfolio.php bit će smještena u mapu modela. Evo njegovog sadržaja:
    klasa Model_Portfolio proširuje model ( javna funkcija get_data() ( return array(array("Year" => "2012", "Site" => "http://DunkelBeer.ru", "Description" => "Dark Dunkel pivo iz njemački proizvođač Löwenbraü proizveden u Rusiji od strane pivarske tvrtke "SUN InBev"."), array("Year" => "2012", "Site" => "http://ZopoMobile.ru", "Description" => "Katalog kineskih Zopo telefona na ruskom jeziku koji se temelje na Android OS-u i dodacima.", // todo); ) )

    Klasa kontrolera modela nalazi se u datoteci controller_portfolio.php, ovdje je njen kod:
    klasa Controller_Portfolio proširuje Controller ( funkcija __construct() ( $this->model = new Model_Portfolio(); $this->view = new View(); ) funkcija action_index() ( $data = $this->model->get_data( ); $this->view->generate("portfolio_view.php", "template_view.php", $data); ) )
    u varijablu podaci zapisuje se niz koji vraća metoda dobiti_podatke, koje smo ranije razmatrali.
    Ova se varijabla zatim prosljeđuje kao parametar metode. generirati, koji se također prosljeđuje: naziv datoteke sa zajedničkim predloškom i naziv datoteke koja sadrži prikaz sa sadržajem stranice.

    Prikaz koji sadrži sadržaj stranice nalazi se u datoteci portfolio_view.php.
    Portfelj

    Svi projekti u sljedećoj tablici su izmišljeni, stoga ni ne pokušavajte slijediti navedene poveznice.
    GodinaProjektOpis


    Ovdje je sve jednostavno, pogled prikazuje podatke primljene od modela.

    2.3.3. Izrada ostalih stranica Ostale stranice izrađuju se na isti način. Njihov kod je dostupan u repozitoriju na GitHubu, poveznica na koju je dana na kraju članka, u odjeljku "Rezultat".3. Rezultat A evo i rezultata:

    Snimka zaslona rezultirajućeg web-mjesta s posjetnicama



    Link na GitHub: https://github.com/vitalyswipe/tinymvc/zipball/v0.1

    Ali u ovoj verziji skicirao sam sljedeće klase (i njihove odgovarajuće tipove):

    • Controller_Login u kojem se generira pregled s formom za unos logina i lozinke, nakon čega se provodi procedura autentifikacije i, ako je uspješna, korisnik se preusmjerava na admin panel.
    • Contorller_Admin s radnjom indeksa koja provjerava je li korisnik prethodno bio ovlašten na web mjestu kao administrator (ako je, prikazuje se administratorski pogled) i akcijom odjave za odjavu.
    Autentifikacija i autorizacija je druga tema, tako da ovdje nije pokrivena, ali je samo gore navedena poveznica data za početak.4. Zaključak MVC uzorak se koristi kao arhitektonska osnova u mnogim okvirima i CMS-ovima koji su kreirani kako bi mogli razviti kvalitativno složenija rješenja u kraćem vremenu. To je omogućeno povećanjem razine apstrakcije, budući da postoji ograničenje složenosti struktura na kojima ljudski mozak može djelovati.

    Ali korištenje web okvira kao što su Yii ili Kohana, koji se sastoje od nekoliko stotina datoteka, pri razvoju jednostavnih web aplikacija (na primjer, stranica s posjetnicama) nije uvijek preporučljivo. Sada možemo stvoriti prekrasan MVC model kako ne bismo miješali Php, Html, CSS i JavaScript kod u jednoj datoteci.

    Ovaj je članak više polazište za učenje CMF-a nego primjer nečeg uistinu ispravnog što možete uzeti kao temelj svoje web aplikacije. Možda vas je to čak i inspiriralo i već razmišljate o pisanju vlastitog microframeworka ili CMS-a temeljenog na MVC-u. No, prije nego što izmislite sljedeći kotač s "mjesečinom i kurvama", razmislite još jednom, možda bi bilo pametnije svoje napore usmjeriti na razvoj i pomoć zajednici postojećeg projekta?!

    P.S.: Članak je prerađen uzimajući u obzir neke od komentara ostavljenih u komentarima. Kritika je bila od velike pomoći. Sudeći po odazivu: komentarima, osobnim apelima i broju korisnika koji su objavu dodali u favorite, ideja za pisanje ove objave nije se pokazala tako lošom. Nažalost, nije moguće uvažiti sve želje i napisati više i detaljnije zbog nedostatka vremena ... ali možda će to učiniti one misteriozne ličnosti koje minus originalnu verziju. Sretno s vašim projektima!

    5. Izbor korisnih poveznica na temu Članak se vrlo često dotiče teme web frameworka - to je vrlo opširna tema, jer se čak i microframeworks sastoji od mnogo komponenti koje su međusobno pametno povezane i bilo bi potrebno više od jedne članak za razgovor o tim komponentama. Ipak, odlučio sam ovdje dati mali izbor linkova (na koje sam otišao dok sam pisao ovaj članak) koji se na ovaj ili onaj način odnose na temu okvira.

    Oznake: Dodajte oznake

    U ovom ćemo članku razumjeti koncept MVC-a i kako ga, uz primjer, možete primijeniti u PHP-u.

    Koncept MVC-a

    MVC (Model-View-Controller, " Model-Pogled-Ponašanje», « Model-View-Controller”) je obrazac dizajna aplikacije u kojem je upravljačka logika podijeljena u tri odvojene komponente na takav način da izmjena jedne od njih ima minimalan utjecaj na ostale.

    MVC predložak dobro je koristiti kod izrade složenih projekata gdje je potrebno odvojiti rad php programera (ili grupu programera podijeliti u odjele), dizajnera, kodera itd.

    MVC obrazac razdvaja prezentaciju, podatke i rukovanje radnjama korisnika u tri odvojene komponente:

    MVC Model (Model). Model pruža podatke (obično View-u) i također odgovara na zahtjeve (obično od kontrolera) promjenom svog stanja.

    MVC pogled. Odgovoran za prikaz informacija (korisničko sučelje).

    MVC ponašanje (kontrolor). Tumači korisnički unos i obavještava model i pogled da reagiraju na odgovarajući način.

    Radi jasnoće, shema MVC uzorka, ilustracija je navedena u nastavku.

    Komponente poput prezentacije i ponašanja ovise o modelu, ali ni na koji način ne utječu na njega. Model može imati više pogleda. Možda je koncept MVC-a teško razumjeti, ali kada se jednom shvati, postaje nezamjenjiv pri razvoju aplikacija u PHP-u.

    MVC u PHP-u

    Posebna značajka kod korištenja MVC-a u PHP-u je da postoji jedna ulazna točka u php aplikaciju, što se, na primjer, postiže na sljedeći način. Kreira se index.php kroz koji će se obrađivati ​​svi zahtjevi, za to kreiramo .htaccess datoteku u mapi s indeksom i u nju postavimo sljedeći kod:

    RewriteEngine na RewriteCond %(REQUEST_FILENAME) !-f RewriteCond %(REQUEST_FILENAME) !-d RewriteRule ^(.*)$ index.php?route=$1

    U navedenom kodu, prvi redak provjerava postojanje tražene datoteke, a ako ne postoji, onda se preusmjerava na index.php, inače će čak i zahtjevi za slike stranice biti preusmjereni na indeks. Posljednji redak koda pretvara zahtjeve poput index.php?route=chat/index u poput index.php/chat/index. Ako ne možete koristiti ModRewrite u svojoj aplikaciji, preusmjeravanje ćete morati izvršiti ručno.

    PHP model

    Podaci o PHP modelu sadržani su u njegovim atributima i mogu se mijenjati samo kroz posebne funkcije. Model može sadržavati više pogleda. U pravilu, phpmodel je klasa koja radi s bazom podataka, točnije: pisanje, čitanje, brisanje. Naravno, čitanje informacija iz baze podataka može se implementirati pomoću nekoliko pogleda (funkcija). Kao primjer, model članaka na stranici: možete dobiti određeni članak iz baze podataka, popis novijih, popularnih, neku kategoriju... sve su to prikazi modela. Radi jasnoće, u nastavku je naveden primjer php modela.

    PHP kontroler (ponašanje)

    PHP kontroleri primaju korisničke zahtjeve koje šaljemo preko index.php te u skladu s njima prilagođavaju rad modela. Ispravnije bi bilo reći da kontroliraju rad php aplikacije.

    PHP prikaz

    Pogled prati promjenu u modelu i stvara ili mijenja php sučelje aplikacije.

    Popis podataka

    Kako radi ovaj PHP MVC predložak?

    Kada korisnik pristupi željenom url-u, odabire se odgovarajući kontroler koji se odnosi na prikaz i model te se prikazuju informacije. Drugim riječima, kontroler u mvc-u je poveznica između modela i pogleda.

    Prednosti MVC uzorka pri izradi PHP aplikacije

    Kao što je gore spomenuto, ovo je, prije svega, diferencijacija programera php stranice u odjele. Brzina php aplikacije također se povećava ako se izradi veliki projekt. Pa, ono što se izravno tiče samog php programera, to je ispravno strukturiranje php koda (sve je na svom mjestu, lakše je razumjeti).

    MVC primjer

    Nećemo se previše zadržavati na primjeru kako MVC radi, jer on već postoji. Samo ću dodati još par dijagrama za dublje razumijevanje.

    Još jedna shema MVC predloška u PHP-u, više je nego razumljiva.

    Uzorak Model-View-Controller (MVC) izuzetno je koristan pri izradi aplikacija sa složenim GUI-jima ili ponašanjima. Ali prikladan je i za jednostavnije slučajeve. U ovom ćemo postu izraditi igru ​​minolovac dizajniranu prema ovom uzorku. Python je odabran kao razvojni jezik, ali to nema neki poseban značaj. Uzorci ne ovise o određenom programskom jeziku i možete jednostavno prenijeti rezultirajuću implementaciju na bilo koju drugu platformu.

    Oglas Ukratko o MVC uzorku

    Kao što ime sugerira, MVC uzorak ima 3 komponente: model, pogled i kontroler. Svaka od komponenti obavlja svoju ulogu i zamjenjiva je. To znači da su komponente međusobno povezane samo nekim jasnim sučeljima iza kojih može stajati svaka implementacija. Ovaj pristup omogućuje zamjenu i kombiniranje različitih komponenti, pružajući potrebnu logiku rada ili izgled aplikacije. Pogledajmo funkcije koje svaka komponenta obavlja.

    Model

    Odgovoran za unutarnju logiku programa. Ovdje možemo sakriti načine pohranjivanja podataka, kao i pravila i algoritme za obradu informacija.

    Na primjer, za jednu aplikaciju možemo izraditi nekoliko modela. Jedan će otklanjati pogreške, a drugi će raditi. Prvi može pohraniti svoje podatke u memoriju ili u datoteku, a drugi već koristi bazu podataka. Zapravo, ovo je samo obrazac strategije.

    Izvođenje

    Odgovoran za prikaz podataka o modelu. Na ovoj razini pružamo samo sučelje za interakciju korisnika s modelom. Smisao uvođenja ove komponente je isti kao iu slučaju pružanja različitih načina pohranjivanja podataka na temelju više Modela.

    Na primjer, u ranim fazama razvoja, možemo stvoriti jednostavan prikaz konzole za našu aplikaciju, a tek onda dodati lijepo dizajniran GUI. Štoviše, ostaje moguće spremiti obje vrste sučelja.

    Osim toga, treba imati na umu da je odgovornost View-a samo pravovremeni prikaz stanja Modela. Kontrolor je odgovoran za obradu radnji korisnika, o čemu ćemo sada govoriti.

    Kontrolor

    Pruža vezu između modela i radnji korisnika koje proizlaze iz interakcije s prikazom. Koordinate kada se ažuriraju stanja modela i prikaza. Donosi većinu odluka o prijelazima aplikacije iz jednog stanja u drugo.

    Zapravo, za svaku radnju koju korisnik može poduzeti u View-u, rukovatelj mora biti definiran u Controller-u. Ovaj rukovatelj će izvršiti odgovarajuće manipulacije na modelu i, ako je potrebno, obavijestiti View o prisutnosti promjena.

    Oglas Specifikacije igre Minesweeper

    Dosta teorije. Sada prijeđimo na praksu. Kako bismo demonstrirali MVC uzorak, napisat ćemo jednostavnu igru: Minolovac. Pravila igre su vrlo jednostavna:

  • Polje za igru ​​je pravokutno područje koje se sastoji od ćelija. Mine se nasumično postavljaju u neke ćelije, ali igrač ne zna za njih;
  • Igrač može kliknuti bilo koju ćeliju polja za igru ​​lijevom ili desnom tipkom miša;
  • Klikom na lijevu tipku miša ćelija se otvara. U ovom slučaju, ako postoji mina u ćeliji, tada igra završava gubitkom. Ako u susjednim ćelijama, pored otvorene, ima mina, tada će se na otvorenoj ćeliji prikazati brojač s brojem mina okolo. Ako oko otvorene ćelije nema mina, tada će se svaka susjedna ćelija otvoriti prema istom principu. To jest, ćelije će se otvarati sve dok ne udare u granicu polja za igru, ili dok ne dođu do već otvorenih ćelija, ili dok se pored njih ne nalazi mina;
  • Klikom na desnu tipku miša možete označiti ćelije. Klik na zatvorenu ćeliju označava je zastavicom koja zaključava njeno stanje i sprječava slučajno otvaranje. Klikom na ćeliju označenu zastavicom njezina se zastavica mijenja u upitnik. U tom slučaju ćelija više nije blokirana i može se otvoriti lijevom tipkom miša. Klikom na ćeliju s upitnikom vraća se neoznačeno zatvoreno stanje;
  • Pobjeda je određena stanjem igre, u kojem su sve ćelije na igralištu otvorene, s izuzetkom miniranih.
  • Primjer onoga što dobivamo prikazan je u nastavku:

    Minolovac UML dijagrami

    Prije nego što prijeđete na pisanje koda, bilo bi lijepo unaprijed razmisliti o arhitekturi aplikacije. Ne bi trebao ovisiti o jeziku implementacije, tako da je UML najprikladniji za naše svrhe.

    Dijagram stanja ćelije igre

    Svaka ćelija na polju za igru ​​može biti u jednom od 4 stanja:

  • Ćelija je zatvorena;
  • Kavez je otvoren;
  • Ćelija je označena;
  • Ćelija je označena upitnikom.
  • Ovdje smo definirali samo stanja koja su relevantna za View. Budući da se mine ne prikazuju tijekom igre, ni odgovarajuće stanje nije predviđeno u osnovnom setu. Definirajmo moguće prijelaze iz jednog stanja ćelije u drugo pomoću UML dijagrama stanja:

    Dijagram klasa minolovaca

    Budući da smo odlučili izgraditi svoju aplikaciju temeljenu na MVC uzorku, imat ćemo tri glavne klase: MinesweeperModel, MinesweeperView i MinesweeperController, kao i pomoćnu klasu MinesweeperCell za pohranjivanje stanja ćelije. Razmotrite njihov dijagram klasa:

    Organizacija arhitekture je vrlo jednostavna. Ovdje smo jednostavno raspodijelili zadatke svakom razredu u skladu s principima MVC uzorka:

  • Na samom dnu hijerarhije nalazi se klasa igraće ćelije MinesweeperCell. Pohranjuje položaj ćelije, određen retkom retkom i stupcem stupca polja za igru; jedno od stanja koje smo opisali u prethodnom pododjeljku; podatak o prisutnosti mina u ćeliji (minirano) i brojač mina u susjednim ćelijama counter . Osim toga, ima dvije metode: nextMark() za kruženje kroz stanja oznake desnog klika i open() , koja obrađuje događaj lijevog klika;
  • Malo viša je klasa MinesweeperModel Model. To je spremnik ćelija igre MinesweeperCell. Njegova prva metoda startGame() priprema teren za igru ​​za početak igre. Metoda isWin() provjerava stanje pobjede u polju za igru ​​i vraća true ako je igrač pobijedio, inače vraća false. Slična metoda isGameOver() namijenjena je provjeri gubitka. Metode openCell() i nextCellMark() samo delegiraju radnje odgovarajućim ćelijama na polju za igru, a metoda getCell() vraća traženu ćeliju igre;
  • Klasa MinesweeperView View uključuje sljedeće metode: syncWithModel() - omogućuje ponovno crtanje View za prikaz trenutnog stanja polja za igru ​​u Modelu; getGameSettings() - vraća postavke igre koje je postavio korisnik; createBoard() - stvara polje za igru ​​na temelju podataka modela; showWinMessage() i showGameOverMessage() redom prikazuju poruke o pobjedi i gubitku;
  • I na kraju klasa MinesweeperController Controller. Definira samo tri metode za svaku moguću akciju igrača: startNewGame() je odgovoran za klik na gumb "Nova igra" u sučelju za prikaz; onLeftClick() i onRightClick() upravljaju klikovima na ćelije igre lijevom odnosno desnom tipkom miša.
  • Implementacija igre Minolovac u Pythonu

    Vrijeme je da krenemo u realizaciju našeg projekta. Izabrat ćemo Python kao razvojni jezik. Zatim ćemo napisati klasu View na temelju modula tkinter.

    Ali počnimo s modelom.

    MinsweeperModel

    Implementacija modela u Pythonu izgleda ovako:

    MIN_ROW_COUNT = 5 MAX_ROW_COUNT = 30 MIN_COLUMN_COUNT = 5 MAX_COLUMN_COUNT = 30 MIN_MINE_COUNT = 1 MAX_MINE_COUNT = 800 klasa MinesweeperCell: # Moguća stanja ćelije igre: # zatvoreno - zatvoreno # otvoreno - otvoreno # označeno - označeno # upitno - označeno upitnikom def __init__ ( self , red, stupac): self.row = red self.column = stupac self.state = "closed" self.mined = False self.counter = 0 markSequence = [ "closed", "flagged", "questioned" ] def nextMark (self): if self.state in self.markSequence: stateIndex = self.markSequence.index(self.state) self.state = self.markSequence[ (stateIndex + 1) % len(self.markSequence) ] def open( self ): if self.state != "flagged": self.state = "opened" class MinesweeperModel: def __init__(self): self.startGame() def startGame(self, rowCount = 15, columnCount = 15, mineCount = 15 ) : if rowCount u rasponu (MIN_ROW_COUNT, MAX_ROW_COUNT + 1): self.rowCount = rowCount if columnCount u rasponu (MIN_COLUMN_COUNT, MAX_COLUMN_COUNT + 1): self.columnCount = columnCount if mineCount< self.rowCount * self.columnCount: if mineCount in range(MIN_MINE_COUNT, MAX_MINE_COUNT + 1): self.mineCount = mineCount else: self.mineCount = self.rowCount * self.columnCount - 1 self.firstStep = True self.gameOver = False self.cellsTable = for row in range(self.rowCount): cellsRow = for column in range(self.columnCount): cellsRow.append(MinesweeperCell(row, column)) self.cellsTable.append(cellsRow) def getCell(self, row, column): if row < 0 or column < 0 or self.rowCount

    povezani članci