Si të konfiguroni telefonat inteligjentë dhe PC. Portali informativ

Kodi i ndarjes. Modeli MVC

Korniza e bootstrap: faqosje e shpejtë e përgjegjshme

Një video tutorial hap pas hapi mbi bazat e paraqitjes së përgjegjshme në kornizën e Bootstrap.

Mësoni të shtypni me lehtësi, shpejt dhe me efikasitet duke përdorur një mjet të fuqishëm dhe praktik.

Paraqitja për të porositur dhe për të paguar.

Kurs falas "Site në WordPress"

Dëshironi të zotëroni një CMS të WordPress?

Merrni mësime mbi hartimin dhe paraqitjen e faqes në internet të WordPress.

Mësoni të punoni me tema dhe të ndani faqosjen.

Kurs falas video për vizatimin e faqes, paraqitjen dhe instalimin në CMS WordPress!

* Lëvizni kursorin e miut për të ndaluar lëvizjen.

Kthehu përpara

Një qasje e përshtatshme për zhvillimin e uebit: Modeli MVC

Çfarë është MVC? Me pak fjalë, kjo është një qasje zhvillimi që ju lejon të arrini kodin më të strukturuar dhe aplikacionin në tërësi.

MVC do të thotë Model-View-Controller. Le të flasim për këtë në më shumë detaje.

Sot, ekzistojnë dy mënyra më tipike për të krijuar aplikacione në internet (faqe).

Mënyra e parë, le ta quajmë "Klasik", supozon se një skedar mund të përmbajë kodin e gjuhëve të ndryshme të programimit dhe shënimin.

Për shembull, në fillim të një skedari, bëhet një pyetje në bazën e të dhënave për të marrë disa informacione prej saj. Këtu kemi të bëjmë me gjuhën SQL - një gjuhë e veçantë e pyetjeve e krijuar për të bashkëvepruar me një bazë të dhënash.

Pas kësaj, si rregull, fillon shënimi html i faqes (ku mund të shkojmë pa të?). Për më tepër, brenda markup-it html, në vendet e duhura, bëhen inserte të kodit PHP, të cilët menaxhojnë faqen, janë logjika e tij. Në përgjithësi, ne kemi në një skedar: SQL, (X) HTML dhe PHP. Ky është tashmë një rrëmujë e ekipit. Mos harroni të shtoni disa CSS të tjera dhe disa Javascript këtu për të plotësuar foton, dhe ne përfundojmë me një rrëmujë të tillë që vetë djalli do t'i thyejë këmbën në këtë skedar.

Sigurisht, në fillim do të mbani mend se çfarë dhe si ndodh në të, pse çfarë nevojitet dhe ku duhet të bëhen ndryshime për të shtuar / hequr / modifikuar funksione të caktuara. Megjithatë, ju garantoj që pas disa muajsh do të shikoni kodin tuaj të hutuar, duke u përpjekur të mbani mend se çfarë lidhet me çfarë, çfarë ndryshimesh do të "tërhiqen" pas ndryshimit të një skedari, etj.

Nuk po them se duhet ta braktisni plotësisht këtë qasje, por është e qartë se duhet përdorur me mençuri dhe me shumë kujdes.

Mënyra e dytëështë e lidhur me përdorimin e skemës "Model-View-Controller".

Cili është thelbi i kësaj qasjeje dhe si mund t'ju ndihmojë përdorimi i saj në punën tuaj?

Ideja kryesore e kësaj qasjeje është nevoja ndarja e elementeve homogjene në skedarë të ndryshëm... E thënë shumë thjesht: një skedar - një gjuhë. Por ky është një shembull shumë i vrazhdë. Kjo është jashtëzakonisht e rrallë.

Përveç idesë së ndarjes së gjuhëve të ndryshme në skedarë të ndryshëm, koncepti kryesor është gjithashtu ndarjen e skedarëve në grupe sipas funksioneve që kryejnë në aplikacion.

Këtu fillojmë me ju për të parë më nga afër modelin MVC.

Ky model nënkupton ndarjen e të gjithë skedarëve të përfshirë në zhvillimin e faqes në tre grupe:

1. Skedarët e grupit "model".
2. Skedarët e grupit "kontrollues".
3. Skedarët e grupit "view".

Është e rëndësishme të kuptohet menjëherë këtu se emri i skemës MVC është një konventë. Në aplikacionin tuaj, natyrisht, mund të ketë shumë modele, kontrollues dhe pamje (d.m.th. skedarë që bien në këto grupe sipas funksioneve dhe strukturës së tyre të brendshme).

Pra, le t'i hedhim një sy një diagram krahasues i modelit MVC dhe mënyrës "klasike" të zhvillimit.


Në të majtë shihni saktësisht atë që folëm më lart. Në krye të faqes - pyetje SQL në bazën e të dhënave. Pastaj futet shënimi plus PHP.

Në të djathtë është diagrami më i thjeshtë i modelit MVC. Në kuadër të kësaj skeme Operacionet që lidhen me ndërveprimin me bazën e të dhënave ndodhin në model: marrja e të dhënave, modifikimi dhe fshirja e tyre, numërimi i numrit të regjistrimeve në tabela të caktuara etj.

Kontrolluesi përmban logjikën e aplikacionit, d.m.th. çfarë përcakton funksionalitetin e tij.

Pamja synohet t'i shfaqet përdoruesit përfundimtar..

Shigjetat me dy drejtime në diagram tregojnë se ekziston një marrëdhënie në çiftet Model - Kontrollues dhe Kontrollues - Shiko. Le ta shqyrtojmë këtë marrëdhënie në më shumë detaje duke përdorur shembullin e diagramit të mëposhtëm.


Në këtë diagram, ne kemi shtuar dy elementë të rinj: shfletuesin e përdoruesit dhe bazën e të dhënave. Le të hedhim një vështrim në të gjithë ciklin: nga shfletuesi që hyn në një url specifik deri në momentin që faqja shfaqet për përdoruesin:

1. Përdoruesi fut adresën dhe shfletuesi kontakton kontrolluesin.

2. Kontrolluesi i referohet modelit.

3. Modeli hyn në bazën e të dhënave (për shembull, për të marrë informacionin e nevojshëm për shfaqjen)

4. Informacioni nga baza e të dhënave kthehet në model.

5. Nga modeli, informacioni transferohet në kontrollues.

6. Kontrolluesi e transferon këtë informacion në pamje.

7. Pamja shfaqet në shfletues duke përdorur kontrolluesin.

Kjo është skema e përgjithshme e funksionimit të këtij modeli. Siç mund ta shihni, shfletuesi dhe baza e të dhënave janë disi të ndryshme në këtë diagram. Vërtet, shfletuesi mund të hyjë vetëm te kontrolluesi pasi kontrolluesi është pjesë e url-së... Vizitori nuk mund të hyjë në asgjë tjetër përveç kontrolluesit. Kjo është e rëndësishme për të kuptuar. Një person nuk mund t'u referohet pamjeve ose modeleve përmes shiritit të adresave. Ai ndërvepron vetëm me kontrolluesin.

Në këtë drejtim, mund të flasim për kontrolluesin si një lloj "qendre shpërndarjeje". Shihni vetë: kontrolluesi trajton kërkesat e përdoruesve, kontrolluesi akseson modelin dhe kontrolluesi ndërmjetëson pamjen në shfletues.

Elementi i dytë që veçohet është baza e të dhënave. Dhe është e drejtë. Brenda konceptit MVC supozohet se vetëm modelet duhet të punojnë me bazën megjithatë, ndonjëherë ky parim shkelet. Në këtë rast, ndërveprimi me bazën bëhet nga kontrolluesi apo edhe pamja.

Sigurisht, nuk duhet të shkoni shumë larg duke shkelur strukturën dhe parimet e MVC, por ndonjëherë një largim i tillë nga rregullat mund të jetë shumë i dobishëm për sa i përket përmirësimit të lexueshmërisë së kodit dhe të kuptuarit se si funksionon aplikacioni.

Model meqe ra fjala, është një element opsional në skemën MVC... Është mjaft e mundur të zbatohet gjithçka që nevojitet pa përdorur modele në parim. Natyrisht, në këtë rast, ju do të ndërveproni me bazën e të dhënave nga kontrolluesi dhe do të shikoni skedarët. Siç e keni kuptuar tashmë, kjo nuk është një formë shumë e mirë. Sapo të vendosni të punoni brenda kornizës së këtij koncepti, rekomandohet të përdorni modelet dhe ta bëni atë për qëllimin e synuar.

Ne ekzaminuam ato "ekstremet", por triniteti ynë mbeti në qendër të diagramit, ku ndodhin ndërveprimet "Model - Kontrollues" dhe "Kontrollues - Pamje".

Pasi të kemi studiuar bazat e këtij modeli, mund të mendojmë se çfarë na jep kjo qasje, pse preferohet nga ajo klasike.

Përfitimi kryesor i përdorimit të një skeme të tillë në punën time është përmendur tashmë - është duke rritur strukturimin e kodit dhe të aplikacionit në tërësi... Nuk është sekret që modeli MVC është miratuar nga shumë shitës të kornizës, duke përfshirë CodeIgniter-in tim të preferuar.

Në fund të fundit, çfarë është një kornizë? Nëse e anashkalojmë fjalën e huaj, atëherë kjo është vetëm një kornizë, një strukturë e caktuar, sipas së cilës ju ftoheni të zhvilloni një faqe interneti. Kjo strukturë është mjaft e gjithanshme për të krijuar pothuajse çdo faqe me të. Në të njëjtën kohë, gjë që është shumë e rëndësishme, korniza është në të njëjtën kohë shumë fleksibël, duke ju lejuar të arrini pikërisht atë që ju nevojitet.

Me fjalë të tjera, një kornizë është një kornizë fleksibël që ju kufizon në aspektin e strukturës, por jo në aspektin e funksionalitetit.

Duke iu rikthyer pyetjes së MVC, mund të shihni se shumë korniza përdorin pikërisht këtë qasje: ato japin një strukturë mjaft të qartë të aplikacionit, në të cilin ekziston edhe një ndarje e skedarëve në pamje, modele dhe kontrollues. E gjithë kjo së bashku mund t'ju kursejë shumë kohë nëse e kaloni një ditë duke mësuar se si të përdorni kornizën dhe modelin MVC.

Përparësi të tjera të modelit MVC përfshijnë ndarja e kodit funksional... Nuk keni më nevojë të gërmoni në rrëmujën e pyetjeve SQL, shënimit dhe kodit PHP. Nëse keni nevojë të rregulloni ose ndryshoni diçka, do të dini saktësisht se cilin skedar duhet të redaktoni.

Më poshtë mund të shihni një pjesë të skedarit që i përket grupit "views":


Dhe këtu është një pjesë e kodit nga modeli:


Kështu mund të duket kontrolluesi:


Një avantazh shumë i rëndësishëm, siç mund ta shihni, është ndarja e pamjes nga kodi... Shpesh është e nevojshme të ndryshoni dizajnin apo edhe strukturën e faqes në një mënyrë ose në një tjetër, duke ruajtur të njëjtin informacion në faqen që ishte shfaqur më parë. Dhe këtu fillon redaktimi i grumbullit të kodeve, i cili me kalimin e kohës bëhet gjithnjë e më i vështirë.

Avantazhi i modelit MVC qëndron pikërisht në mundësinë e plotë përjashtoni modifikimin e dizajnit të faqes kur ndryshoni logjikën e aplikacionit... Ju mund të ndryshoni cilindo nga tre elementët: Modeli, Pamja, Kontrolluesi. Në këtë rast, nuk keni pse të bëni ndryshime në elementë të tjerë, pasi ato janë në një farë mase autonome.

Çështja e autonomisë për modelet dhe pamjet është veçanërisht e rëndësishme. Pasi t'i keni shkruar ato, zakonisht mund t'i përdorni me sukses për projekte të ndryshme me modifikime minimale ose pa modifikime. Kjo ju kursen shumë kohë duke eliminuar nevojën për të rishkruar kode të ngjashme.

Përparësitë e përdorimit të modelit MVC brenda kornizës janë të qarta, për shembull, i njëjti CodeIgniter.

Nuk është sekret që çdo faqe ka një numër të madh funksionesh të ngjashme, nëse jo plotësisht identike. Mjafton të kujtoni formularin e komenteve ose navigimin e faqes. Këto janë vetëm momentet më goditëse, "të jashtme". Do të gjeni edhe më shumë ngjashmëri në kodin që nuk është i dukshëm për përdoruesin mesatar, në kodin që funksionon në server.

Pothuajse të gjithë zhvilluesit e uebit përballen me nevojën për të përdorur funksione të ngjashme PHP, për të bërë pyetje të ngjashme me bazën e të dhënave, etj. Shitësit e kornizës bënë një gjë shumë të rëndësishme këtu - ata u përpoqën të grupojnë ato funksione që përdoren më shpesh në skedarë të veçantë, duke u dhënë webmasterëve dhe programuesve të uebit mundësi të reja.

Tani mund të kryeni gjërat që nevojiten shpesh pa menduar vërtet se cili është zbatimi i tyre. Ju mund të shkruani disa rreshta kodi në vend të disa dhjetëra rreshtave, duke kursyer kohën tuaj dhe duke u fokusuar më shumë në logjikën e aplikacionit, sesa në mënyrën e zbatimit të tij.

Dhe e gjithë kjo ndodh brenda kornizës së konceptit MVC, duke ju lejuar të arrini pothuajse çdo rezultat duke përdorur kornizën. Duke vepruar kështu, ju merrni një shkallë të lartë të lexueshmërisë së kodit. Çfarë tjetër ju nevojitet për punë komode dhe efikase?

Pasthënia: Mbani në mend se çdo strukturë që është krijuar për ta bërë më të lehtë realizimin e një detyre të caktuar është krijuar pikërisht për ta bërë më të lehtë.

Shmangni ngjitjen në MVC kur jeni të sigurt se është e dëmshme për të kuptuarit tuaj të strukturës së aplikacionit. Ju nuk duhet të "përkuleni" nën modelin, por atë nën ju.

Dmitry Naumenko

P.S. Pyesni se cilën kornizë PHP të zotëroni? Kushtojini vëmendje CakePHP - ai zbaton modelin MVC të diskutuar më lart, dhe tani mund të merrni një hyrje të shpejtë në video për të marrë një ide të përgjithshme të aftësive të këtij kuadri:

Ju pëlqeu materiali dhe dëshironi t'ju falënderoni?
Thjesht ndajeni me miqtë dhe kolegët tuaj!


Modeli Model-View-Controller (MVC) është jashtëzakonisht i dobishëm për ndërtimin e aplikacioneve me ndërfaqe ose sjellje komplekse grafike të përdoruesit. Por për raste më të thjeshta, do të funksionojë gjithashtu. Në këtë postim, ne do të krijojmë një lojë sapper bazuar në këtë model. Python u zgjodh si gjuha e zhvillimit, por nuk ka asnjë kuptim të veçantë në këtë. Modelet nuk varen nga një gjuhë programimi specifike, dhe ju lehtë mund ta transferoni zbatimin që rezulton në çdo platformë tjetër.

Reklamim

Shkurtimisht për modelin MVC

Siç sugjeron emri, modeli MVC përfshin 3 komponentë: Model, Pamje dhe Kontrollues. Secili nga komponentët përmbush rolin e tij dhe është i këmbyeshëm. Kjo do të thotë që komponentët janë të lidhur me njëri-tjetrin vetëm nga disa ndërfaqe të qarta, pas të cilave mund të qëndrojë çdo zbatim. Kjo qasje ju lejon të zëvendësoni dhe kombinoni komponentë të ndryshëm, duke siguruar logjikën e nevojshme të punës ose pamjen e aplikacionit. Le të shohim funksionet që kryen secili komponent.

Model

Përgjegjës për logjikën e brendshme të programit. Këtu mund të fshehim metodat e ruajtjes së të dhënave, si dhe rregullat dhe algoritmet për përpunimin e informacionit.

Për shembull, për një aplikacion, ne mund të krijojmë disa modele. Njëri do të korrigjojë dhe tjetri do të funksionojë. I pari mund të ruajë të dhënat e tij në memorie ose në një skedar, ndërsa i dyti tashmë po përdor bazën e të dhënave. Në fakt, ky është vetëm një model Strategjie.

Përfaqësimi

Përgjegjës për shfaqjen e të dhënave të Modelit. Në këtë nivel, ne ofrojmë vetëm një ndërfaqe për ndërveprimin e përdoruesit me Modelin. Qëllimi i prezantimit të këtij komponenti është i njëjtë me ofrimin e mënyrave të ndryshme të ruajtjes së të dhënave bazuar në disa Modele.

Për shembull, në fazat e hershme të zhvillimit, ne mund të krijojmë një pamje të thjeshtë të konsolës për aplikacionin tonë dhe vetëm atëherë të shtojmë një GUI të dizajnuar bukur. Për më tepër, mbetet e mundur të mbahen të dy llojet e ndërfaqeve.

Për më tepër, duhet të kihet parasysh se përgjegjësia e View është vetëm për të shfaqur në kohë gjendjen e Modelit. Kontrolluesi është përgjegjës për përpunimin e veprimeve të përdoruesit, për të cilat do të flasim tani.

Kontrolluesi

Ofron një lidhje midis modelit dhe veprimeve të përdoruesit që rezultojnë nga ndërveprimi me Pamjen. Koordinon momentet e përditësimit të gjendjeve të Modelit dhe Pamjes. Merr shumicën e vendimeve për kalimin e një aplikacioni nga një shtet në tjetrin.

Në fakt, për çdo veprim që një përdorues mund të bëjë në një View, një mbajtës duhet të përcaktohet në Controller. Ky mbajtës do të kryejë manipulimet e duhura në model dhe, nëse është e nevojshme, do të informojë Pamjen për ndryshimet.

Reklamim

Specifikimet e lojës Minesweeper

Mjaft teori. Tani le të zbresim në praktikë. Për të demonstruar modelin MVC, ne do të shkruajmë një lojë të thjeshtë: Minesweeper. Rregullat e lojës janë mjaft të thjeshta:

  1. Fusha e lojës është një zonë drejtkëndore e përbërë nga qeliza. Në disa qeliza, minat janë të vendosura rastësisht, por lojtari nuk di për to;
  2. Lojtari mund të klikojë në çdo qelizë të fushës së lojës me butonin e majtë ose të djathtë të miut;
  3. Duke klikuar butonin e majtë të miut do të hapet qeliza. Për më tepër, nëse ka një minierë në qeli, atëherë loja përfundon me humbje. Nëse ka mina në qelizat ngjitur, pranë një qelize të hapur, atëherë një numërues me numrin e minave përreth do të shfaqet në qelizën e hapur. Nëse nuk ka miniera rreth një qelize të hapur, atëherë çdo qelizë ngjitur do të hapet sipas të njëjtit parim. Kjo do të thotë, qelitë do të hapen derisa ose të qëndrojnë në kufirin e fushës së lojës, ose të arrijnë në qelitë tashmë të hapura, ose të mos ketë asnjë minierë pranë tyre;
  4. Klikimi i butonit të djathtë të miut ju lejon të bëni shënime në qeliza. Klikimi mbi një qelizë të mbyllur e shënon atë me një flamur, i cili bllokon gjendjen e tij dhe parandalon hapjen aksidentale. Klikimi në një kuti të shënuar me një flamur e ndryshon flamurin e tij në një pikëpyetje. Në këtë rast, qeliza nuk është më e bllokuar dhe mund të hapet me butonin e majtë të miut. Klikimi në një qelizë me pikëpyetje e kthen atë në gjendjen e mbyllur të pashënuar;
  5. Fitorja përcaktohet nga gjendja e lojës, në të cilën të gjitha qelizat në fushën e lojës janë të hapura, përveç atyre të minuara.

Një shembull i asaj që marrim tregohet më poshtë:

Diagramet UML të Minesweeper

Përpara se të vazhdoni me shkrimin e kodit, është mirë të mendoni paraprakisht për arkitekturën e aplikacionit. Ajo duhet të jetë e pavarur nga gjuha e zbatimit, kështu që UML është më e përshtatshme për qëllimet tona.

Loja Diagrami i gjendjes së qelizave

Çdo qelizë në fushën e lojës mund të jetë në një nga 4 gjendjet:

  1. Kafazi është i mbyllur;
  2. Kafazi është i hapur;
  3. Qeliza është e shënuar me një flamur;
  4. Qeliza shënohet me pikëpyetje.

Këtu kemi përcaktuar vetëm gjendjet që kanë kuptim për Pamjen. Meqenëse minat nuk shfaqen gjatë lojës, nuk ka gjendje përkatëse në grupin bazë. Le të përcaktojmë kalimet e mundshme nga një gjendje qelize në tjetrën duke përdorur Diagramin e Gjendjes UML:

Diagrami i klasës së minahedhësit

Meqenëse vendosëm të krijojmë aplikacionin tonë bazuar në modelin MVC, do të kemi tre klasa kryesore: MinesweeperModel, MinesweeperView dhe MinesweeperController, si dhe një klasë ndihmëse MinesweeperCell për ruajtjen e gjendjes së burgut. Merrni parasysh diagramin e tyre të klasës:

Organizimi i arkitekturës është mjaft i drejtpërdrejtë. Këtu ne thjesht kemi caktuar detyra për secilën klasë në përputhje me parimet e modelit MVC:

  1. Në fund të hierarkisë është klasa MinesweeperCell e qelizës së lojës. Ai ruan pozicionin e qelizës, të specifikuar nga rreshti i rreshtit dhe kolona e fushës së lojës; një nga shtetet thotë që kemi përshkruar në nënseksionin e mëparshëm; informacion për praninë e një mine në qeli (minuar) dhe numëruesin e minave në sportelin e qelive fqinje. Për më tepër, ai ka dy metoda: nextMark (), i cili kalon nëpër gjendjet e lidhura me shenjat e klikuar me të djathtën dhe hapja (), e cila trajton ngjarjen e klikimit të majtë.
  2. Më sipër është klasa Modeli MinesweeperModel. Është enë për MinesweeperCells. Metoda e saj e parë startGame () përgatit fushën e lojës për fillimin e lojës. Metoda isWin () kontrollon fushën e lojës për një gjendje fituese dhe kthen true nëse lojtari fiton, përndryshe kthen false. Një metodë e ngjashme isGameOver () përdoret për të kontrolluar humbjen. Metodat openCell () dhe nextCellMark () delegojnë veprime vetëm në qelizat përkatëse në fushën e lojës, dhe metoda getCell () kthen qelizën e kërkuar të lojës;
  3. Klasa MinesweeperView e View përfshin metodat e mëposhtme: syncWithModel () - siguron rivizatimin e View për të shfaqur gjendjen aktuale të fushës së lojës në Model; getGameSettings () - kthen cilësimet e lojës të specifikuara nga përdoruesi; createBoard () - krijon një fushë loje bazuar në të dhënat e Modelit; showWinMessage () dhe showGameOverMessage () shfaqin përkatësisht mesazhet fituese dhe humbëse;
  4. Së fundi, klasa Controller është MinesweeperController. Ai përcakton vetëm tre metoda për çdo veprim të mundshëm të lojtarit: startNewGame () është përgjegjës për shtypjen e butonit "New Game" në ndërfaqen View; onLeftClick () dhe onRightClick () trajtojnë klikimet në qelizat e lojës me butonin e majtë dhe të djathtë të miut, përkatësisht.

Zbatimi i lojës Minesweeper në Python

Është koha për të filluar zbatimin e projektit tonë. Le të zgjedhim Python si gjuhë të zhvillimit. Më pas do të shkruajmë klasën View bazuar në modulin tkinter.

Por le të fillojmë me Modelin.

MinsweeperModel

Zbatimi i modelit në Python është si më poshtë:

MIN_ROW_COUNT = 5 MAX_ROW_COUNT = 30 MIN_COLUMN_COUNT = 5 MAX_COLUMN_COUNT = 30 MIN_MINE_COUNT = 1 MAX_MINE_COUNT = 800 klasë MinesweeperCell: # Gjendjet e mundshme të lojës: # e mbyllur me një pyetje - e mbyllur # me një #rresht të hapur - , kolona): self.row = rresht self.column = kolona self.state = "mbyllur" self.mined = False self.counter = 0 markSequence = ["mbyllur", "i flamur", "i pyetur"] def nextMark (vetë ): nëse vetë.state në vetvete.markSequence: StateIndex = vet.markSequence.index (self.state) self.state = self.markSequence [(stateIndex + 1)% len (self.markSequence)] def open (self ): nëse self.state! = "me flamur": self.state = klasë "e hapur" MinesweeperModel: def __init __ (vetë): self.startGame () def startGame (vetë, rowCount = 15, columnCount = 15, mineCount = 15) : nëse numërimi i rreshtave në interval (MIN_ROW_COUNT, MAX_ROW_COUNT + 1): vetë.Numri i rreshtave = Numri i rreshtave nëse numri i kolonave në interval (MIN_COLUMN_COUNT, MAX_COLUMN_COUNT + 1): self.columnCount = Count Count nëse 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 <= row or self.columnCount <= column: return None return self.cellsTable[ row ][ column ] def isWin(self): for row in range(self.rowCount): for column in range(self.columnCount): cell = self.cellsTable[ row ][ column ] if not cell.mined and (cell.state != "opened" and cell.state != "flagged"): return False return True def isGameOver(self): return self.gameOver def openCell(self, row, column): cell = self.getCell(row, column) if not cell: return cell.open() if cell.mined: self.gameOver = True return if self.firstStep: self.firstStep = False self.generateMines() cell.counter = self.countMinesAroundCell(row, column) if cell.counter == 0: neighbours = self.getCellNeighbours(row, column) for n in neighbours: if n.state == "closed": self.openCell(n.row, n.column) def nextCellMark(self, row, column): cell = self.getCell(row, column) if cell: cell.nextMark() def generateMines(self): for i in range(self.mineCount): while True: row = random.randint(0, self.rowCount - 1) column = random.randint(0, self.columnCount - 1) cell = self.getCell(row, column) if not cell.state == "opened" and not cell.mined: cell.mined = True break def countMinesAroundCell(self, row, column): neighbours = self.getCellNeighbours(row, column) return sum(1 for n in neighbours if n.mined) def getCellNeighbours(self, row, column): neighbours = for r in range(row - 1, row + 2): neighbours.append(self.getCell(r, column - 1)) if r != row: neighbours.append(self.getCell(r, column)) neighbours.append(self.getCell(r, column + 1)) return filter(lambda n: n is not None, neighbours)

Në krye, ne përcaktojmë gamën e cilësimeve të vlefshme të lojës:

MIN_ROW_COUNT = 5 MAX_ROW_COUNT = 30 MIN_COLUMN_COUNT = 5 MAX_COLUMN_COUNT = 30 MIN_MINE_COUNT = 1 MAX_MINE_COUNT = 800

Në përgjithësi, këto cilësime mund të bëhen gjithashtu pjesë e Modelit. Megjithatë, madhësia e fushës dhe numri i minave janë informacion mjaft statik dhe nuk ka gjasa të ndryshojnë shpesh.

Më pas përcaktuam klasën MinesweeperCell për qelizën e lojës. Doli të ishte mjaft e thjeshtë. Në konstruktorin e klasës, fushat e qelizës inicializohen me vlerat e paracaktuara. Më pas, për të thjeshtuar zbatimin e tranzicioneve të gjendjes ciklike, ne përdorim listën ndihmëse të markës Sequence. Nëse qeliza është në gjendjen "e hapur", e cila nuk përfshihet në këtë listë, atëherë asgjë nuk do të ndodhë në metodën nextMark (), përndryshe qeliza hyn në gjendjen tjetër, dhe nga gjendja e fundit "e pyetur" ajo "kërce" në gjendjen fillestare "të mbyllur". Në metodën e hapur (), kontrollojmë gjendjen e qelizës, dhe nëse nuk është e barabartë me "e flamur", atëherë qeliza kalon në gjendjen "e hapur".

Më poshtë është përkufizimi i klasës MinesweeperModel Model. Metoda startGame () rregullon fushën e lojës sipas parametrave rowCount, columnCount dhe mineCount që i kalohen asaj. Për secilin prej parametrave, kryhet një kontroll për t'u siguruar që ai bie brenda intervalit të pranueshëm të vlerave. Nëse vlera e transmetuar është jashtë rrezes, atëherë vlera e parametrit të fushës së lojës nuk ndryshon. Duhet të theksohet se është parashikuar një kontroll shtesë për numrin e minierave. Nëse numri i transferuar i minave tejkalon madhësinë e fushës, atëherë ne e kufizojmë atë në numrin e qelizave pa një. Edhe pse, sigurisht, një lojë e tillë nuk ka shumë kuptim dhe do të përfundojë në një hap, kështu që ju mund të gjeni disa nga rregullat tuaja për një rast të tillë.

Tabela e lojës ruhet si një listë me lista qelizash në variablincellTable. Për më tepër, vini re se në metodën startGame (), vendoset vetëm vlera e pozicionit për qelizat, por minat ende nuk janë vendosur. Në vend të kësaj, ndryshorja firstStep përcaktohet me vlerën True. Kjo është e nevojshme për të hequr elementin e rastësisë nga lëvizja e parë dhe për të parandaluar humbjen e menjëhershme. Minat do të vendosen pas lëvizjes së parë në qelitë e mbetura.

Metoda getCell () thjesht e kthen qelizën e fushës së lojës sipas rreshtit dhe kolonës. Nëse vlera e rreshtit ose kolonës është e pavlefshme, atëherë "Asnjë" kthehet.

Metoda isWin () kthen True nëse të gjitha qelizat e mbetura të pahapura të fushës së lojës janë minuar, domethënë në rast fitoreje, përndryshe do të kthehet False. Metoda isGameOver () thjesht kthen vlerën e atributit të klasës gameOver.

Në metodën openCell (), thirrja e hapur () i delegohet objektit të qelizës së lojës, i cili ndodhet në fushën e lojës në pozicionin e specifikuar në parametrat e metodës. Nëse qeliza e hapur rezulton e minuar, atëherë vendosim vlerën e gameOver në True dhe dalim nga metoda. Nëse loja nuk ka përfunduar ende, atëherë shohim nëse kjo është lëvizja e parë duke kontrolluar vlerën e firstStep. Nëse lëvizja është me të vërtetë e para, atëherë minat do të vendosen në fushën e lojës duke përdorur metodën ndihmëse të gjenerimit Mines (), për të cilën do të flasim pak më vonë. Më pas, ne numërojmë numrin e qelizave fqinje të minuara dhe vendosim vlerën përkatëse të atributit numërues për qelizën e përpunuar. Nëse numëruesi është zero, atëherë kërkojmë një listë të qelizave fqinje duke përdorur metodën getCellNeighbors () dhe thërrasim në mënyrë rekursive metodën openCell () për të gjithë "fqinjët" e mbyllur, domethënë për qelizat me statusin "mbyllur".

Metoda nextCellMark () thjesht delegon thirrjen në metodën nextMark () për qelizën e vendosur në pozicionin e kaluar.

Rregullimi i minave ndodh në metodën gjenerimMines (). Këtu thjesht zgjedhim rastësisht një pozicion në fushën e lojës dhe kontrollojmë që qeliza në këtë pozicion të mos jetë e hapur dhe jo tashmë e minuar. Nëse plotësohen të dyja kushtet, atëherë e vendosim vlerën e atributit të minuar në True, përndryshe vazhdojmë të kërkojmë një qelizë tjetër të lirë. Mos harroni se për të përdorur modulin e rastësishëm në Python, duhet ta importoni atë në mënyrë eksplicite me komandën import rastësore.

Metoda e numërimit të numrit të minave që numërohen MinesAroundCell () rreth një qelize të caktuar të fushës së lojës bazohet tërësisht në metodën getCellNeighbors (). Kërkesa për "fqinjët" e qelizës në metodën getCellNeighbors () është gjithashtu shumë e thjeshtë. Unë nuk mendoj se do të keni problem me të.

MinesweeperView

Tani le të zbresim te prezantimi. Kodi për klasën MinesweeperView në Python tregohet më poshtë:

Klasa MinesweeperView (Frame): def __init __ (vetë, model, kontrollues, prind = Asnjë): Frame .__ init __ (vetë, prind) self.model = model self.controller = kontrollues self.controller.setView (vetë) vetë .createBoard ( ) panel = Kornizë (vetë) panel.paketë (ana = POSHT, mbush = X) Butoni (panel, tekst = "Lojë e re", komanda = self.controller.startNewGame) .paketë (ana = Djathtas) vetë. mineCount = StringVar (panel) self.mineCount.set (self.model.mineCount) Kuti rrotulluese (paneli, nga_ = MIN_MINE_COUNT, në = MAX_MINE_COUNT, variabël teksti = self.mineCount, gjerësia = 5) .paketë (ana = Djathtas) Etiketa (paneli , text = "Numri i minave:") .pack (ana = Djathtas) self.rowCount = StringVar (panel) self.rowCount.set (self.model.rowCount) Spinbox (panel, nga_ = MIN_ROW_COUNT, në = MAX_ROW_COUNT, variabël teksti = self.rowCount , width = 5) .pack (ana = RIGHT) Label (panel, text = "x") .pack (ana = RIGHT) self.columnCount = StringVar (panel) self.columnCount.set (self.model .columnCount) Kuti rrotulluese (paneli, nga_ = MIN_COLUMN_COUN T, në = MAX_COLUMN_COUNT, variabël teksti = self.columnCount, gjerësi = 5) .pack (ana = Djathtas) Etiketa (paneli, teksti = "Madhësia e fushës:") .paketë (ana = Djathtas) def syncWithModel (vetë): për rreshtin në varg (self.model.rowCount): për kolonën në varg (self.model.columnCount): cell = self.model.getCell (rresht, kolonë) nëse qeliza: btn = self.buttonsTabela [rresht] [kolona] nëse vetë .model.isGameOver () dhe cell.mined: btn.config (bg = "e zezë", tekst = "") nëse cell.state == "mbyllur": btn.config (tekst = "") elif cell.state = = "e hapur": btn.config (lehtësim = SUNKEN, tekst = "") nëse cell.counter> 0: btn.config (tekst = cell.counter) elif cell.mined: btn.config (bg = "e kuqe") elif cell.state == "me flamur": btn.config (tekst = "P") elif cell.state == "i pyetur": btn.config (tekst = "?") def blockCell (vetë, rresht, kolonë, bllok = E vërtetë): btn = vetë.buttonsTabela [rresht] [kolona] nëse jo btn: ktheje nëse blloku: btn.bind (" "," thyej ") else: btn.unbind (" ") def getGameSettings (vetë): kthe self.rowCount.get (), self.columnCount.get (), self.mineCount.get () def createBoard (vetë): provo: self.board.pack_forget () self.board .destroy () self.rowCount.set (self.model.rowCount) self.columnCount.set (self.model.columnCount) self.mineCount.set (self.model.mineCount) përveç: kaloj vetë.board = Frame (vetë ) self.board.pack () self.buttonsTable = për rreshtin në varg (self.model.rowCount): rresht = Kornizë (self.board) line.pack (ana = TOP) self.buttonsRew = për kolonën në varg (vetë .model.columnCount): btn = Butoni (rreshti, gjerësia = 2, lartësia = 1, komanda = rreshti lambda = rreshti, kolona = kolona: self.controller.onLeftClick (rresht, kolonë), padx = 0, pady = 0) btn.pack (ana = Majtas) btn.bind (" ", lambda e, rresht = rresht, kolonë = kolonë: self.controller.onRightClick (rresht, kolonë)) self.buttonsRow.append (btn) self.buttonsTable.append (self.buttonsRow) def showWinMessage (vetë): showinfo ( "Urime!", "Ti fitove!") Def showGameOverMessage (vetë): showinfo ("Loja mbaroi!", "Ti humbe!")

Pamja jonë bazohet në klasën Frame nga moduli tkinter, prandaj mos harroni të ekzekutoni komandën e duhur të importit: nga tkinter import *. Modeli dhe Controller kalohen në konstruktorin e klasës. Metoda CreativeBoard () thirret menjëherë për të kompozuar fushën e lojës nga qelizat. Do të them paraprakisht se për këtë qëllim do të përdorim Butonat e zakonshëm. Pastaj krijohet një Frame, e cila do të veprojë si paneli i poshtëm për specifikimin e parametrave të lojës. Në këtë panel, ne vendosim në mënyrë sekuenciale butonin "Lojë e re", mbajtësi i të cilit bëhet Kontrolluesi ynë me metodën e tij startNewGame () dhe më pas tre numërues Spinbox në mënyrë që lojtari të tregojë madhësinë e fushës së lojës dhe numrin e minave. .

Metoda syncWithModel () thjesht kalon nëpër secilën qelizë në një lak të dyfishtë dhe ndryshon pamjen e butonit që e përfaqëson atë në GUI-në tonë. Për hir të thjeshtësisë, kam përdorur simbole teksti për shfaqjen e simboleve, por nuk është aq e vështirë të ndryshosh tekstin në grafikë nga skedarët grafikë të jashtëm.

Gjithashtu, vini re se ne po përdorim stilin e butonit SUNKEN për të përfaqësuar qelizën e hapur. Dhe në rast humbjeje, hapni vendndodhjen e të gjitha minave në fushën e lojës, duke treguar butonat përkatës në të zezë dhe theksoni butonin që korrespondon me qelizën e fundit të hapur me një minierë në të kuqe:

Metoda tjetër blockCell () shërben si ndihmëse dhe lejon kontrolluesin të vendosë gjendjen e bllokimit për butonat. Kjo është e nevojshme për të parandaluar hapjen aksidentale të qelizave të lojës të shënuara me një flamur dhe arrihet duke instaluar një mbajtës bosh për klikim të butonit të majtë të miut.

Metoda getGameSettings () kthen vetëm vlerat e numëruesve të vendosur në panelin e poshtëm me madhësinë e fushës së lojës dhe numrin e minave.

Pamja e fushës së lojës krijohet në metodën createBoard (). Para së gjithash, ka një përpjekje për të fshirë fushën e vjetër të lojës, nëse ka ekzistuar, dhe ne gjithashtu përpiqemi të vendosim vlerat e numëruesve nga paneli në përputhje me konfigurimin aktual të Modelit. Pastaj krijohet një kornizë e re, të cilën do ta quajmë tabelë, për të përfaqësuar fushën e lojës. Ne e kompozojmë tabelën e butonave të tabelës në të njëjtën mënyrë si qelizat e lojës në Model duke përdorur një lak të dyfishtë. Trajtuesit e secilit buton janë bashkangjitur me metodat onLeftClick () dhe onRightClick () të Kontrolluesit për klikimet majtas dhe djathtas të miut, respektivisht.

Dy metodat e fundit showWinMessage () dhe showGameOverMessage () thjesht shfaqin kutitë e dialogut me mesazhe të përshtatshme duke përdorur funksionin showinfo (). Për ta përdorur atë, duhet të importoni një modul tjetër: nga tkinter.messagebox import *.

Kontrolluesi i minave

Pra, arritëm në zbatimin e Kontrolluesit:

Klasa MinesweeperController: def __init __ (vetë, modeli): vet.model = model përcaktohenView (vetë, pamje): vetë.pamje = shiko fillimin e riLojë (vetë): lojëSettings = self.view.getGameSettings () provo: self.model . startGame (* harta (int, GameCettings)) përveç: self.model.startGame (self.model.rowCount, self.model.columnCount, self.model.mineCount) self.view.createBoard () def onLeftClick (vetë, rresht , kolonë): self.model.openCell (rresht, kolonë) self.view.syncWithModel () if self.model.isWin (): self.view.showWinMessage () self.startNewGame () elif self.model.isGameOver () : self.view.showGameOverMessage () self.startNewGame () def onDjathtasClick (vetë, rresht, kolonë): self.model.nextCellMark (rresht, kolonë) self.view.blockCell (rresht, kolonë, self.model.getCell (rresht , kolona) .state == "e shënuar") self.view.syncWithModel ()

Ne kemi shtuar metodën setView () për të lidhur View me Controller. Kjo ndodh sepse nëse do të donim t'i kalonim një pamje konstruktorit, atëherë kjo pamje do të duhej të ekzistonte tashmë përpara se të krijohej kontrolluesi. Dhe pastaj një zgjidhje e ngjashme me një metodë shtesë për lidhjen thjesht do të kalonte nga Controller në View, në të cilën do të shfaqej metoda setController ().

Metoda e mbajtësit startNewGame () për të klikuar në butonin Lojë e re kërkon fillimisht parametrat e lojës të futura në View. Parametrat e lojës kthehen si një tufë prej tre komponentësh, të cilët po përpiqemi t'i konvertojmë në int. Nëse gjithçka shkon mirë, atëherë ne i kalojmë këto vlera në metodën startGame () të Modelit për të ndërtuar fushën e lojës. Nëse diçka shkon keq, ne thjesht do të rikrijojmë fushën e lojës me parametrat e vjetër. Së fundi, ne dërgojmë një kërkesë për të krijuar një shfaqje të re të tabelës së lojës në View duke thirrur metodën createBoard ().

Trajtuesi onLeftClick () së pari udhëzon Modelin të hapë qelizën e lojës në pozicionin e zgjedhur të lojtarit. Më pas informon View se gjendja e Modelit ka ndryshuar dhe sugjeron rivizatimin e gjithçkaje. Pastaj Modeli kontrollohet për një gjendje fituese ose humbje. Nëse ndodh ndonjë nga këto, atëherë së pari dërgohet një kërkesë në View për të shfaqur njoftimin përkatës dhe më pas thirret mbajtësi startNewGame () për të filluar një lojë të re.

Klikimi me të djathtën trajtohet në metodën onRightClick (). Në rreshtin e parë, metoda nextCellMark () e Modelit thirret për të ndryshuar ciklikisht etiketën e qelizës së zgjedhur të lojës. Në varësi të gjendjes së re të qelizës, një kërkesë dërgohet në View për të vendosur ose zhbllokuar butonin përkatës. Dhe në fund, Pamja përditësohet përsëri për të shfaqur gjendjen aktuale të Modelit.

Kombinimi i modelit, pamjes dhe kontrolluesit

Tani gjithçka që mbetet është të lidhim të gjithë elementët brenda zbatimit tonë të Minesweeper bazuar në modelin MVC dhe të fillojmë lojën:

Model = MinesweeperModel () kontrollues = MinesweeperController (model); pamje = MinesweeperView (model, kontrollues) view.pack () view.mainloop ()

konkluzioni

Pra, ne shikuam modelin MVC. Ne kaluam shkurtimisht teorinë. Dhe më pas, hap pas hapi, ne krijuam një aplikacion loje të plotë, duke kaluar nga vendosja e problemit dhe dizajnimi i arkitekturës në zbatimin në gjuhën e programimit Python duke përdorur modulin grafik tkinter.

Modeli Model-View-Controller (MVC), i zbuluar në fund të viteve 1970, është një model dizajni i arkitekturës softuerike që fokusohet në shkëputjen e funksioneve të të dhënave nga prezantimi i tyre. Në teori, një aplikacion MVC i dizajnuar mirë do t'u lejojë zhvilluesve të nivelit të përparmë dhe atij të fundit të mos ndërhyjnë në fushat e përgjegjësisë së njëri-tjetrit gjatë punës së tyre, domethënë, zhvilluesi i pjesës së përparme nuk ka nevojë të dijë asgjë për "kuzhinën". " të kolegut të tij të fundit dhe anasjelltas.

Edhe pse fillimisht i projektuar për zhvillimin e aplikacioneve desktop, MVC është përshtatur për nevojat e sotme dhe është jashtëzakonisht popullor me zhvilluesit e uebit, sepse ndarja e shqetësimeve ka bërë të mundur krijimin e kodit më të qartë dhe të ripërdorshëm. Modeli MVC rezulton në sisteme të qarta, modulare që lejojnë zhvilluesit të bëjnë ndryshime në kodin ekzistues shumë shpejt.

Në këtë artikull, ne do t'ju ecim me bazat e MVC, duke filluar duke përcaktuar një model dhe duke vazhduar me një shembull të vogël. Ky artikull do të jetë kryesisht i dobishëm për ata që nuk e kanë hasur kurrë këtë model në jetën e tyre, dhe gjithashtu, ndoshta, për ata që dëshirojnë të mësojnë njohuritë e tyre për MVC.

Kuptimi i MVC

Siç është përmendur tashmë, emri i modelit vjen nga shkurtimi i tre fjalëve: Model Pamje dhe Kontrolluesi... Shkurtimisht, parimi i modelit mund të ilustrohet me një diagram (mund të gjendet në Wikipedia):

Ky diagram tregon qartë rrjedhën e njëanshme të informacionit në model, dhe gjithashtu përshkruan rolet e secilit komponent.

Model

Modeli përdoret për të aksesuar dhe manipuluar të dhënat. Në shumicën e rasteve, një model është ai që përdoret për të hyrë në një dyqan të dhënash (siç është një bazë të dhënash). Modeli ofron një ndërfaqe për marrjen, krijimin, modifikimin dhe fshirjen e të dhënave nga ruajtja. Në kontekstin e modelit MVC, modeli ndërmjetëson midis pamjes dhe kontrolluesit.

Një tipar jashtëzakonisht i rëndësishëm i modelit është se ai teknikisht nuk ka njohuri se çfarë po ndodh me të dhënat në kontrollues dhe pamjen. Modeli kurrë nuk duhet të bëjë ose të presë ndonjë kërkesë për / nga komponentët e tjerë të modelit.

Sidoqoftë, mbani mend gjithmonë se një model nuk është vetëm një portë për një bazë të dhënash ose sistem tjetër që nuk bën asgjë tjetër veçse i kalon të dhënat përpara dhe mbrapa. Një model është si një portë për të dhëna. Modeli është në shumicën e rasteve pjesa më komplekse e sistemit, pjesërisht sepse vetë modeli është ngjitës për të gjitha pjesët e tjera.

Përfaqësimi

Pamja është ajo ku të dhënat e marra nga modeli shfaqen në formën e dëshiruar. Në aplikacionet tradicionale të ueb-it të zhvilluara me modelin MVC, një pamje është pjesa e sistemit ku gjenerohet HTML. Pamja është gjithashtu përgjegjëse për marrjen e veprimeve nga përdoruesi në mënyrë që t'i dërgojë ato te kontrolluesi. Për shembull, një pamje jep një buton në ndërfaqen e përdoruesit, dhe pasi e klikoni atë, thërret veprimin përkatës të kontrolluesit.

Ka disa keqkuptime rreth qëllimit të pamjes, veçanërisht midis zhvilluesve të uebit që sapo kanë filluar të ndërtojnë aplikacionet e tyre duke përdorur MVC. Një nga rregullat që shkelen më shpesh është se pamja nuk duhet të komunikojë me modelin në asnjë mënyrë, dhe të gjitha të dhënat e marra nga pamja duhet të vijnë vetëm nga kontrolluesi... Në praktikë, zhvilluesit shpesh e injorojnë këtë koncept, i cili është në thelb të modelit MVC. Artikulli i Fabio Cevasco ilustron këtë qasje konfuze ndaj MVC duke përdorur CakePHP, një nga shumë korniza jo standarde MVC:

Është jashtëzakonisht e rëndësishme të kuptohet se për të marrë arkitekturën e saktë MVC, nuk duhet të ketë ndërveprime të drejtpërdrejta midis pamjeve dhe modeleve. E gjithë logjika e shkëmbimit të të dhënave ndërmjet tyre duhet të zbatohet në kontrollues.

Përveç kësaj, ekziston një keqkuptim i zakonshëm që një pamje është thjesht një skedar shabllon. Siç vuri në dukje Tom Butler, ky keqkuptim ka një shkallë të madhe për faktin se shumë zhvillues e keqkuptojnë strukturën MVC që në fillim, pas së cilës ata fillojnë ta derdhin këtë "dije" më tej, masat e zhvilluesve fillestarë. Në realitet, një pamje është shumë më tepër sesa thjesht një shabllon, megjithatë, shumë korniza të ndërtuara mbi bazën e modelit MVC e kanë shtrembëruar konceptin e një pamjeje aq shumë sa që askujt nuk i intereson se sa korrekte janë aplikimet e tyre nga pikëpamja e Modeli MVC.

Është gjithashtu e rëndësishme që pamja të mos funksionojë kurrë me të dhëna "të pastra" nga kontrolluesi, domethënë kontrolluesi nuk punon kurrë me pamjen duke anashkaluar modelin. Në procesin e ndërveprimit ndërmjet kontrolluesit dhe pamjes, modeli duhet të jetë gjithmonë ndërmjet tyre.

Kontrolluesi

Kontrolluesi është pjesa e fundit e grupit MVC. Detyra e kontrolluesit është të marrë të dhëna nga përdoruesi dhe të manipulojë modelin. Është kontrolluesi, dhe vetëm ai, që është pjesa e sistemit që ndërvepron me përdoruesin.

Me pak fjalë, një kontrollues mund të përshkruhet si një mbledhës informacioni që e transferon atë në një model për përpunim dhe ruajtje. Ai nuk duhet të bëjë asgjë me të dhënat, por vetëm të jetë në gjendje t'i marrë ato nga përdoruesi. Kontrolluesi shoqërohet me një pamje dhe një model, duke organizuar kështu një rrjedhë të dhënash të njëanshme, duke e kontrolluar atë në çdo fazë.

Është shumë e rëndësishme të mbani mend se kontrolluesi fillon punën e tij vetëm si rezultat i ndërveprimit të përdoruesit me pamjen, e cila thërret funksionin përkatës të kontrolluesit. Gabimi më i zakonshëm midis zhvilluesve është trajtimi i një kontrolluesi thjesht si një portë midis pamjes dhe modelit. Si rezultat, kontrolluesi është i pajisur me funksionet që duhet të kryejë pamja (nga rruga, këtu vjen ideja se pamja është vetëm një skedar shabllon). Për më tepër, shumë njerëz hedhin fare logjikën e përpunimit të të dhënave, duke harruar se për çfarë synohet modeli në modelin MVC.

MVC në PHP

Unë sugjeroj të përpiqeni të zbatoni sa më sipër në një aplikacion të vogël. Le të fillojmë duke krijuar klasat Model, View dhe Controller:

string = "MVC + PHP = I mrekullueshëm!"; ))kontrollues = kontrollues $; $ kjo->

". vargu $ this-> model->."

"; } } model = modeli $; ))

Klasat kryesore janë gati. Tani, le t'i lidhim ato së bashku dhe të ekzekutojmë aplikacionin tonë:

prodhimi ();

Siç mund ta shihni, kontrolluesi nuk ka funksionalitet sepse përdoruesi nuk ndërvepron me aplikacionin në asnjë mënyrë. I gjithë funksionaliteti vendoset në pamje, pasi aplikacioni ynë është vetëm për shfaqjen e të dhënave.

Le ta zgjerojmë pak aplikacionin duke shtuar një interaktivitet për të parë se si funksionon kontrolluesi:

string = “MVC + PHP = E mrekullueshme, kliko këtu!”; ))kontrollues = kontrollues $; $ ky-> modeli = modeli $; ) prodhimi i funksionit publik () (kthimi "

model-> varg. "

"; } } model = modeli $; ) funksioni publik i klikuar () ($ this-> model-> string = “Të dhënat e përditësuara, falë MVC dhe PHP!”))

Më në fund, le të përditësojmë pak kodin e ngjitësit:

($ _GET ["veprim"]) (); ) echo $ view-> output ();

Rezultatet

Në këtë artikull të shkurtër, ne mbuluam konceptet bazë të modelit të dizajnit MVC dhe zhvilluam një aplikacion të thjeshtë bazuar në të, megjithëse sigurisht që jemi ende shumë larg përdorimit të tij në jetën reale. Në artikullin vijues, do të shohim vështirësitë kryesore me të cilat do të përballeni nëse jeni më të fokusuar në ndërtimin e një arkitekture aplikacioni bazuar në modelin MVC. Qëndroni të sintonizuar!

Zhvillimi i një aplikacioni në përputhje me modelin e dizajnit MVC (Model-View-Controller) është karakteristikë e Java-s dhe në lidhje me DroidScript duket e pakuptueshme dhe e panevojshme. Pse i komplikojmë gjërat? MVC fitoi një aureolë kompleksiteti dhe "magjie" për shkak të përdorimit të fjalëve të bukura, por të pakuptueshme (koncept, model, logjikë biznesi, model) dhe demonstrime komplekse në kontekstin e Java kur e konsideron atë. Është shumë më e thjeshtë: MVC është një nga modelet e dizajnit që bën shtesëkodin e ndarjes në objekt të orientuar mjedisi.

Elementi qendror i modelit MVC është kontrolluesi - një aplikacion i rregullt DroidScript, nga i cili nxirret kodi që lidhet me shënimin vizual dhe pamjen e miniaplikacioneve, si dhe të dhënat dhe metodat e hyrjes në to. Nga të dhënat, ne jemi mësuar të kuptojmë informacionin e ruajtur në grupe, skedarë, baza të të dhënave. Por në konceptin MVC, të dhënat kuptohen në kuptimin e gjerë të fjalës - është gjithçka që nuk është kod aplikimi:

  • të dhëna të jashtme nga skedarët dhe bazat e të dhënave - meta të dhënat, teksti, grafika, tingujt, muzika, etj.
  • të dhëna të brendshme të aplikacionit - linja me etiketa në butona dhe kontrolle të tjera, tekst në kuti dialogu, përshkrime të stileve, konstante, grafika të krijuara në mënyrë programore, etj.

Nga këndvështrimi i përdoruesit, puna e tij me aplikacionin duke përdorur MVC nuk ka ndryshuar: ai gjithashtu klikon mbi butona, zgjedh të dhënat dhe si shfaqen ato. Ndryshimet mund të shqetësojnë objektet të kësaj pune. Dhe nga ana e zhvillimit, ndryshimet janë të prekshme: ndërveprimi midis të dhënave dhe shfaqjes së tyre në konceptin MVC ndodh përmes kontrollorit dhe nën kontrollin e tij.

Le të fillojmë duke parë një shembull të thjeshtë të përdorimit të MVC në një aplikacion të vetëm skedari.

Zbatimi i MVC me një skedar të vetëm

Le të marrim një aplikim të thjeshtë.

Funksioni OnStart () (var _lay = app.CreateLayout ("linear", "VCenter, FillXY"); var _btnShowVersion = app.CreateButton ("Trego versionin", 0.3, 0.1); _btnShowVersion.SetBackColor ("89767"); _btnShowVersion.SetMargins (0, 0.05, 0, 0); _btnShowVersion.SetOnTouch (funksioni () (_btnShowVersion.SetText ("Versioni i aplikacionit 1.0");));

Në pamje të parë, gjithçka duket mirë, por supozoni se dëshironi të ndryshoni skemën e ngjyrave të aplikacionit dhe të shfaqni etiketat në disa gjuhë. Kjo do të çojë në komplikime, pasi të gjitha të dhënat në shembullin e treguar janë vlera fikse (literale). Kjo redukton ndjeshëm fleksibilitetin e kodit dhe e bën më të vështirë korrigjimin dhe mirëmbajtjen.

Një pengesë tjetër është se të dhënat - etiketat në buton, shënimi - metodat për shfaqjen e miniaplikacioneve dhe veprimin - blloku i kodit që ndryshon etiketën në butonin kur klikoni mbi të, janë në një bllok dhe në një skedar. . Kjo do të thotë, për të ndryshuar etiketën, duhet të hapni këtë skedar dhe të fitoni akses në të gjithë kodin e aplikacionit. Është sikur për të zëvendësuar timonin e një makine, duhej të çmontoje trupin e makinës për të pasur akses në të gjithë përmbajtjen. Per cfare? Në procesin e çmontimit të trupit të makinës, mund të lidhni aksidentalisht diçka dhe ta bëni atë jofunksionale. Është gjithashtu e mundur në kod: Doja të zëvendësoja emrin e rreshtit në një vend, por zëvendësimi ndodhi në të gjithë skedarin, gjë që çoi në shfaqjen e një shpërndarje gabimesh. Ose thjesht doja të ndryshoja ngjyrën e butonit, por aksidentalisht u lidha me kodin aty pranë dhe i gjithë aplikacioni pushoi së punuari.

Një nga detyrat e modelit MVC është pikërisht diferencimi i aksesit: fillimisht përcaktohet moduli (ose blloku i kodit) që është burimi i gabimit dhe më pas jepet vetëm qasja në të. Pse të jepni akses në elektronikën dhe motorin e makinës, nëse keni nevojë të zëvendësoni timonin?

Nëse zhvillimi kryhet në një skedar, atëherë shpesh ndodh kështu: funksionet e reja vendosen në vend, në fillim ose në fund të kodit, gjë që përfundimisht çon në përzierjen e tyre. Le të shtojmë këtu përzierjen e kodit në vetë funksionet, dhe në një muaj, edhe me komente, nuk do të jetë e lehtë ta kuptosh.

Le të zbatojmë shembullin e treguar më sipër në kontekstin e MVC. Për ta bërë këtë, i gjithë kodi duhet të ndahet dhe grupohet në blloqet e duhura. Renditja e blloqeve në kod nuk është e rëndësishme, por është më mirë t'i përmbaheni logjikës: që kontrolluesi të funksionojë, nevojiten të dhëna dhe elemente për t'i shfaqur ato, kështu që ai vendoset i fundit. Në kohën kur shfaqen të dhënat, ato duhet të ekzistojnë. Pra, blloku i modelit vjen i pari:

  1. Model
  2. Përfaqësimi
  3. Kontrolluesi
// +++ modeli (funksioni () (var _obj =; // +++ të dhënat var _version = "Versioni i aplikacionit 1.0"; var _titleShowVersion = "Trego versionin"; // --- të dhënat
// +++ metoda publike për aksesimin e të dhënave _obj.getVersion = funksion () (kthim _version;) _obj.btnGetTitle = funksion () (kthim _titleShowVersion;) // --- metoda publike për qasje në dritaren e të dhënave.model = _obj; // qasje e hapur në objektin lokal)) (); // --- model // +++ pamje (funksioni () (var _lay = app.CreateLayout ("linear", "VCenter, FillXY"); var _btnShowVersion = app.CreateButton (window.model.btnGetTitle (), 0.3, 0.1); _btnShowVersion.name = "_btnShowVersion"; _btnShowVersion.SetBackColor ("# 66778976"); _btnShowVersion.SetMargins (0, 0.05, 0, 0, 0)C; _lay.

)) (); // --- pamje // +++ kontrolluesi (funksioni (p_object) (var _obj =; // metoda e kërkimit të objektit publik _obj.findObjectById = funksioni (p_name) (var _objectList = app.GetObjects (); për (var _i në _objectList) (nëse (_objectList [_i] .emri == p_emri) (kthimi _objectList [_i];)) kthej null;) dritaren.control = _obj;)) (); funksioni OnStart () (var _buttonShowVersion = window.control.findObjectById ("_ btnShowVersion"); // +++ veprimi _buttonShowVersion.SetOnTouch (funksioni () (this.SetText (window.model.getVersion ()); / / --- veprim) // --- kontrollues

Për shkak të ndarjes së funksioneve, kodi i aplikacionit është rritur disa herë.

Fillimisht, të gjitha variablat bëhen private dhe vetëm në fund, nëse është e nevojshme, hapet qasja në to përmes objektit të dritares globale, gjë që bën të mundur që të bëhet pa variabla globale.

Shembulli zbaton kërkimin për një widget, si në Java, por mund ta bëni më të lehtë dhe ta bëni kodin më efikas duke hapur aksesin në objekt përmes grupit shoqërues global:

Dritarja.kontrollet =;
window.controls.buttonShowVersion = _btnShowVersion;

Të dhënat, shfaqja e tyre dhe reagimi ndaj veprimeve janë në blloqe të ndryshme, pa u përzier me njëra-tjetrën, gjë që e bën më të lehtë për zhvilluesin të punojë me to. Sa më e lehtë të jetë të punosh me të dhëna dhe kode, aq më pak gabime do të ketë, aq më e lehtë do të jetë korrigjimi, mirëmbajtja dhe shkallëzimi.

Nuk është e nevojshme të ndahen të tre nga njëri-tjetri. Ekzistojnë disa variacione të MVC, si dhe implementime jo të plota të këtij modeli. Për shembull, mund të shkëputni të dhënat dhe të kombinoni kodin e veprimit me kontrollet duke përdorur funksione anonime të kthimit të thirrjes.

Kur punoni në një mjedis të orientuar nga objekti, ndarja e kodit dhe të dhënave është tashmë e pranishme fillimisht: të dhënat dhe veprimet grupohen në klasa, objektet ndërveprojnë me njëri-tjetrin përmes metodave publike, etj. Falë MVC, ka një ndarje më delikate dhe të qartë të kodit dhe të dhënave sipas funksioneve të tyre kryesore.

Për një kuptim më të thellë të përfitimeve të përdorimit të modelit MVC, merrni parasysh ndarjen e kodit tuaj në skedarë të veçantë.

Zbatimi me tre skedarë i modelit MVC

Ndarja e kodit në skedarë të ndryshëm përdoret për punë më të përshtatshme me të. Numri i madh i skedarëve të vegjël që mund të shihen në projektet MVC mund të vënë në dyshim këtë deklaratë, por të shohësh skedarë është një gjë, por të punosh me ta është krejt tjetër. Në çdo moment, zhvilluesi ndërvepron me një skedar nga një grup i vogël i tyre. Për ta bërë këtë, ju duhet të keni një kuptim të mirë të strukturës së organizatës së projektit dhe të monitoroni vazhdimisht skedarë të trefishtë- modeli, pamja dhe kontrolluesi, në mënyrë që të mos modifikoni aksidentalisht kodin e palëve të treta. Për shkak të kufizimeve të redaktuesit të DroidScript, ky grupim është i mundur vetëm sipas emrave të skedarëve në direktorinë rrënjësore, për shembull:

myproject_model.js - model
myproject_view.js - pamje
myproject_control.js - kontrollues

Më poshtë është një shembull i ndarjes së kodit të shembullit të mëparshëm në skedarë.

myproject_model.js - model(funksioni () (var _obj =; // +++ të dhëna var _version = "Versioni i aplikacionit 1.0"; // --- të dhëna // +++ burimi i vargut var _titleShowVersion = "Trego versionin"; // +++ burimi i vargut _obj.getVersion = funksioni () (kthimi _versioni;) _obj.btnGetTitle = funksioni () (kthimi _titleShowVersion;) dritare.model = _obj;)) (); myproject_view.js - pamje(funksioni () (var _lay = app.CreateLayout ("linear", "VCenter, FillXY"); var _btnShowVersion = app.CreateButton (window.model.btnGetTitle (), 0.3, 0.1); _btnShowVersion.namenShow = "_bt _btnShowVersion.SetBackColor ("# 66778976"); _btnShowVersion.SetMargins (0, 0.05, 0, 0); _lay.AddChild (_btnShowVersion); app.AddLayout (_lay);)) (); myproject_control.js - kontrollues app.LoadScript ("myproject_model.js"); app.LoadScript ("myproject_view.js");(funksioni (p_object) (var _obj =; // metoda e kërkimit të objektit _obj.findObjectById = funksioni (p_name) (var _objectList = app.GetObjects (); për (var _i në _objectList) (nëse (_objectList [_i] .emri = = p_emri) (kthimi _objectList [_i];)) kthen null;) dritare.control = _obj;)) (); funksioni OnStart () (var _buttonShowVersion = window.control.findObjectById ("_ btnShowVersion"); // +++ veprimi _buttonShowVersion.SetOnTouch (funksioni () (this.SetText (window.model.getVersion ()); / / --- veprim )

Kjo ndarje e thjeshtë e kodit në skedarë nuk ishte e lehtë. Për këtë, një lidhje me modelin u krijua paraprakisht përmes pronës publike të objektit rrënjë global - dritare.model, dhe komunikimi me pamjen përmes grupit global _hartë përmes metodës app.GetObjects.

Avantazhi i ndarjes së kodit në skedarë është se tani ju mund ta zëvendësoni kodin me një bllok të tërë, për shembull, të nisni shpejt një projekt, të zbatoni një model të thjeshtë dhe më pas të zëvendësoni skedarin me një tjetër më funksional, por me të njëjtën emri dhe ndërfaqja. Kjo qasje përdoret, për shembull, kur riparoni pajisje. Nëse më parë riparimi konsistonte në një kërkim të ngadaltë dhe të mundimshëm dhe zëvendësim të komponentëve të dështuar të radios, tani blloqet standarde po zëvendësohen. Kostoja e riparimit të një bordi kompleks është dukshëm më e lartë se zëvendësimi i tij i shpejtë.

Nga sa u tha, rrjedh se një ndërfaqe e mirë-projektuar bën të mundur thjeshtimin e ndjeshëm të integrimit të mëvonshëm të moduleve.

Në JavaScript, objektet kalohen me referencë. Ndryshimi i vetive të miniaplikacionit në kontrollues do të ndryshojë vetitë shumica widget. Teorikisht, është e mundur të ndahen objektet e prezantimit nga objektet e kodit, siç bëhet në Java, ku strukturat xml përdoren si të parat, por nuk ka shumë kuptim në këtë për dy arsye - mungesën e një redaktuesi të ndërfaqes vizuale në DroidScript dhe një grup i kufizuar i vetive të disponueshme të objekteve API.

Implementimi me shumë skedarë i modelit MVC

Në varësi të detyrave dhe kompleksitetit të projektit, detajet e ndarjes së kodit dhe të dhënave, në rastin e përgjithshëm, mund të jenë të ndryshme. Gjithashtu, mund t'i ndani të dhënat e përdoruesit nga burimet, mund t'i analizoni burimet sipas llojit, veprimeve në grup, etj. Por, redaktori i DroidScript nuk lejon punën MVC me funksione të plota.

Emërtimi 5000 rubla

Numri (rs 8225497)

Imitim i një kartëmonedhe origjinale të Bankës së Rusisë të vitit 1997

Letër. Nuk fluoreshon në rrezet UV

Metoda e printimit. Printim i sheshtë offset - të gjitha imazhet. Paraqitja e ngjyrave është e shtrembëruar. Të gjitha imazhet kanë një shkëlqim karakteristik. Formohet nga pika me ngjyra. Në vendet e kthesave vërehet derdhje e bojës.

TIPARET MBROJTËSE PUBLIKE. ANA E PËRPARME

Filigranë (1,2)


Imituar nga mbishtypja me një substancë të bardhë në anën e përparme. Imazhet e shtrembëruara të filigranëve shihen në dritën e reflektuar

Imazhi latent (efekti kipp) (3)


Nuk riprodhohet

Fijet mbrojtëse

Simuluar nga mbishtypja. Në rrezet UV vërehet shkëlqim jeshil dhe i kuq.

Ngjyrë e ndryshueshme me ngjyra (4)


Imazhi i stemës ka një shkëlqim të shtuar. Efekti OVI nuk riprodhohet

MVC + Elementi (5)


I pa imituar. Linjat Moire të efektit MVC vërehen nga çdo kënd shikimi; u shfaq gjatë kopjimit nga origjinali.

Mikroperforim (6)


Simuluar. Vrima mikro-shpuese të shikuara në dritën e reflektuar

Llak i ndryshueshëm (7)

Stema e Bankës së Rusisë është e mbuluar me bojë të artë. Efekti polarizues nuk riprodhohet.

Stampim pa ngjyrë (8)

I pa imituar

Lehtësim

I pa imituar

Emërtimi 5000 rubla

Numri (rs 8225497)

Një imitim i një kartëmonedhe origjinale të Bankës së Rusisë të vitit 1997.

TIPARET MBROJTËSE PUBLIKE. ANËSIA E PASME

Mikrotekst (9,10)


Riprodhuar pjesërisht

Fije sigurie (11)


Imituar nga një substancë e bardhë në anën e përparme, rezultatet imitohen nga stampimi me fletë metalike. Daljet e fillit të sigurisë vështirë se dallohen.

KARAKTERISTIKAT E MBROJTJES TË lexueshme nga makina

Mbrojtje lumineshente

I imituar pjesërisht

Mbrojtje IR

I imituar pjesërisht

Mbrojtje magnetike

I pa imituar

Shënim. Sipas agjencive të zbatimit të ligjit të Federatës Ruse, kartëmonedha e falsifikuar u sekuestrua në Territorin e Permit.

Materiali i përgatitur IPK "InterCrim-press".

Artikujt kryesorë të lidhur