Cum se configurează smartphone-uri și PC-uri. Portal informativ

Distribuie codul. Model MVC

Cadru bootstrap: aspect adaptiv rapid

Curs video pas cu pas despre elementele de bază ale aspectului adaptiv în cadrul Bootstrap.

Aflați cum să scrieți simplu, rapid și eficient folosind un instrument puternic și practic.

Aspect pentru a comanda și a fi plătit.

Curs gratuit „Site pe WordPress”

Vrei să stăpânești CMS-ul WordPress?

Obțineți lecții despre design și aspectul site-ului web pe WordPress.

Învață să lucrezi cu teme și să tăiați machete.

Curs video gratuit despre desenarea unui site web, aspect și instalare pe CMS WordPress!

* Treceți mouse-ul peste pentru a întrerupe derularea.

Inapoi inainte

O abordare prietenoasă a dezvoltării web: modelul MVC

Ce este MVC? Pe scurt, este o abordare a dezvoltării care vă permite să obțineți un cod mai structurat și aplicația în ansamblu.

MVC înseamnă Model-View-Controller. Să vorbim despre asta mai detaliat.

Astăzi, există două modalități cele mai tipice de a crea aplicații web (site-uri).

Prima cale, să-l numim „Clasic”, presupune că un fișier poate conține cod pentru diferite limbaje de programare și de marcare.

Să presupunem că la începutul fișierului se face o interogare la baza de date pentru a obține unele informații din aceasta. Aici avem de-a face cu limbajul SQL - un limbaj de interogare special conceput pentru a interacționa cu o bază de date.

După aceasta, de regulă, începe marcarea html a paginii (unde am fi noi fără el?). Mai mult, în interiorul markupului html, codul PHP este introdus în locurile potrivite, ceea ce controlează site-ul și este logica acestuia. În total, avem într-un singur fișier: SQL, (X)HTML și PHP. Aceasta este deja un amestec. Nu uitați să adăugați mai multe CSS și puțin Javascript aici pentru a completa imaginea, iar la final vom obține o asemenea mizerie încât diavolul însuși își va rupe piciorul în acest fișier.

Desigur, la început vă veți aminti ce și cum se întâmplă în el, de ce aveți nevoie de el și unde trebuie să faceți modificări pentru a adăuga/elimina/modifica anumite funcționalități. Cu toate acestea, vă garantez că în câteva luni vă veți uita la codul cu nedumerire, încercând să vă amintiți ce este conectat la ce, ce modificări vor fi „implementate” după modificarea unui fișier etc.

Nu spun că această abordare ar trebui abandonată complet, dar este clar că trebuie folosită cu înțelepciune și cu mare grijă.

A doua cale legate tocmai de utilizarea schemei „Model-View-Controller”.

Care este esența acestei abordări și cum vă poate ajuta utilizarea ei în munca dvs.?

Ideea principală a acestei abordări este nevoia separarea elementelor omogene în fişiere diferite. Pentru a spune foarte simplu: un fișier - o limbă. Dar acesta este un exemplu foarte dur. Acest lucru este extrem de rar.

Pe lângă ideea de a păstra diferite limbi în fișiere diferite, conceptul cheie este și împărțirea fișierelor în grupuri în funcție de funcțiile pe care le îndeplinesc în aplicație.

Aici începem să abordăm modelul MVC mai detaliat.

Acest model presupune împărțirea tuturor fișierelor implicate în dezvoltarea site-ului web în trei grupe:

1. Fișiere din grupul „model”.
2. Fișierele grupului „controller”.
3. Fișierele grupului „vizualizare”.

Aici este important să înțelegeți imediat că numele schemei MVC este o convenție. Aplicația dvs., desigur, poate avea multe modele, controlere și vederi (adică fișiere care se încadrează în aceste grupuri în funcție de funcțiile pe care le îndeplinesc și de structura lor internă).

Deci să ne uităm la diagramă comparativă a modelului MVC și a metodei de dezvoltare „clasică”..


În partea stângă vezi exact despre ce am vorbit mai sus. În partea de sus a paginii sunt interogări SQL către baza de date. Apoi markup plus inserții PHP.

În dreapta este cea mai simplă diagramă a modelului MVC. În cadrul acestei scheme în model apar operațiuni legate de interacțiunea cu baza de date: preluarea datelor, modificarea și ștergerea acestora, numărarea numărului de înregistrări din anumite tabele etc.

Controlerul conține logica aplicației, adică ceea ce îi determină funcţionalitatea.

Vizualizarea este destinată a fi afișată utilizatorului final.

Săgețile cu două capete din diagramă arată că există o relație în perechile „Model - Controler” și „Controller - Vizualizare”. Să luăm în considerare această relație mai detaliat folosind următoarea diagramă ca exemplu.


În această diagramă, am adăugat două elemente noi: browserul utilizatorului și baza de date. Să ne uităm la întregul ciclu în termeni generali: din browser accesând o anumită adresă URL până când pagina este afișată utilizatorului:

1. Utilizatorul introduce adresa și browserul contactează controlorul.

2. Controlerul accesează modelul.

3. Modelul accesează baza de date (de exemplu, pentru a obține informații necesare pentru ieșire)

4. Informațiile din baza de date se întorc la model.

5. Informațiile sunt transferate de la model la controler.

6. Controlorul transmite aceste informații către vizualizare.

7. Vizualizarea este afișată în browser folosind controlerul.

Aceasta este schema generală de funcționare a acestui model. După cum puteți vedea, browserul și baza de date se evidențiază oarecum separat în această diagramă. Într-adevăr, browserul poate accesa controlerul doar deoarece controlerul face parte din URL. Vizitatorul nu poate accesa altceva decât controlorul. Acest lucru este important de înțeles. O persoană nu poate accesa vizualizări sau modele prin bara de adrese. Interacționează doar cu controlerul.

În acest sens, putem vorbi despre controler ca un fel de „centru de distribuție”. Vedeți singuri: controlorul procesează cererile utilizatorilor, controlorul accesează modelul, iar controlorul este un intermediar pentru afișarea vizualizării în browser.

Al doilea element care se deosebește este baza de date. Și este corect. În cadrul conceptului MVC, se acceptă faptul că Doar modelele ar trebui să funcționeze cu baza de date, totuși, uneori acest principiu este încălcat. În acest caz, interacțiunea cu baza de date se realizează dintr-un controler sau chiar dintr-o vizualizare.

Desigur, nu ar trebui să mergeți prea departe și să încălcați structura și principiile MVC, dar uneori o astfel de abatere de la reguli poate fi foarte utilă în ceea ce privește îmbunătățirea lizibilității codului și înțelegerea schemei de funcționare a aplicației.

Model, apropo, este un element opțional în schema MVC. Este foarte posibil să implementați tot ce aveți nevoie fără a utiliza deloc modele. Desigur, în acest caz veți interacționa cu baza de date din controler și veți vedea fișiere. După cum ați înțeles deja, aceasta nu este o formă foarte bună. Odată ce decideți să lucrați în cadrul acestui concept, este recomandat să utilizați modele și să faceți acest lucru în scopul propus.

Ne-am uitat la „extreme”, dar în centrul diagramei a rămas trinitatea noastră, unde au loc interacțiunile „Model - Controler” și „Controller - Vizualizare”.

După ce am studiat elementele de bază ale acestui model, ne putem gândi ce ne oferă această abordare și de ce este de preferat celui clasic.

Principalul beneficiu al utilizării unei astfel de scheme în munca dvs. a fost deja menționat - acesta creșterea structurii codului și a aplicației în ansamblu. Nu este un secret pentru nimeni că modelul MVC a fost adoptat de mulți producători de cadre, inclusiv CodeIgniter-ul meu preferat.

La urma urmei, ce este un cadru? Dacă aruncăm cuvântul străin, atunci acesta este pur și simplu un cadru, o anumită structură conform căreia vi se cere să dezvoltați un site web. Această structură este suficient de universală pentru a crea aproape orice site web cu ajutorul ei. În același timp, ceea ce este foarte important, cadrul este și foarte flexibil, permițându-vă să realizați exact ceea ce aveți nevoie.

Cu alte cuvinte, un cadru este un cadru flexibil care te limitează din punct de vedere al structurii, dar nu te limitează din punct de vedere al funcționalității.

Revenind la întrebarea despre MVC, putem observa că multe cadre folosesc exact această abordare: oferă o structură a aplicației destul de clară, care împarte fișierele în tipuri, modele și controlere. Toate acestea împreună vă pot economisi mult timp dacă îl petreceți o dată învățând cum să utilizați cadrul și modelul MVC.

Alte avantaje ale modelului MVC includ împărțirea codului în funcție de funcționalitate. Nu va mai trebui să cercetați în mizeria interogărilor SQL, a marcajului și a codului PHP. Dacă trebuie să corectați sau să modificați ceva, veți ști exact ce fișier trebuie să editați.

Mai jos puteți vedea o parte din fișierul aparținând grupului „vizualizări”:


Și iată o bucată de cod din model:


Iată cum ar putea arăta controlerul:


Un avantaj foarte important, după cum puteți vedea, este separarea vederii de cod. Adesea este necesar să se schimbe cumva designul sau chiar structura site-ului, păstrând în același timp aceleași informații pe pagina care era afișată înainte. Și aici începe editarea amestecului de cod, care devine din ce în ce mai dificil în timp.

Avantajul modelului MVC constă tocmai în capacitatea de a completa excludeți editarea designului site-ului atunci când schimbați logica aplicației. Puteți schimba oricare dintre cele trei elemente: Model, View, Controller. În acest caz, nu trebuie să faceți modificări asupra altor elemente, deoarece acestea sunt într-o anumită măsură autonome.

Problema autonomiei este deosebit de relevantă pentru modele și specii. Odată ce le-ați scris, de obicei le puteți utiliza cu succes pentru o varietate de proiecte cu modificări minime sau fără modificări. Acest lucru vă economisește mult timp prin rescrierea unui cod similar.

Avantajele utilizării modelului MVC în cadru sunt evidente, de exemplu, același CodeIgniter.

Nu este un secret pentru nimeni că fiecare site web are un număr mare de funcții similare sau chiar identice. Nu uitați decât formularul de feedback sau navigarea în pagină. Acestea sunt doar cele mai izbitoare momente „externe”. Veți găsi și mai multe asemănări în codul care nu este vizibil pentru utilizatorul obișnuit, în codul care rulează pe server.

Aproape toți dezvoltatorii web se confruntă cu nevoia de a utiliza funcții PHP similare, de a efectua interogări similare în baze de date etc. Producătorii de cadre au făcut un lucru foarte important aici - au încercat să grupeze acele funcții care sunt utilizate cel mai des în fișiere separate, oferind webmasterilor și programatorilor web noi oportunități.

Acum puteți face lucruri de care aveți nevoie frecvent fără să vă gândiți prea mult la modul în care vor fi implementate. Puteți scrie câteva rânduri de cod în loc de câteva zeci de linii, economisind timp și concentrându-se mai mult pe logica modului în care funcționează aplicația decât pe modul de implementare.

Și toate acestea se întâmplă în cadrul conceptului MVC, permițându-vă să obțineți aproape orice rezultate folosind cadrul. În același timp, obțineți un grad ridicat de lizibilitate a codului. Ce altceva ai nevoie pentru o muncă confortabilă și productivă?

Postfaţă: Amintiți-vă că orice structură care a fost creată pentru a ușura anumite sarcini a fost creată pentru a ușura munca.

Nu ar trebui să respectați principiul MVC în cazurile în care sunteți sigur că are un efect negativ asupra înțelegerii dvs. a structurii aplicației. Nu tu ar trebui să te „pleci” sub model, ci modelul sub tine.

Dmitri Naumenko

P.S. Te gândești ce framework PHP să stăpânești? Fiți atenți la CakePHP - implementează modelul MVC discutat mai sus și chiar acum puteți obține un scurt curs video introductiv pentru a vă face o idee generală despre capacitățile acestui cadru:

Ți-a plăcut materialul și vrei să-mi mulțumești?
Distribuie doar prietenilor și colegilor tăi!


Modelul Model-View-Controller (MVC) este extrem de util atunci când se creează aplicații cu GUI sau comportament complex. Dar este potrivit și pentru cazuri mai simple. În această postare vom crea un joc de mine, conceput pe baza acestui model. Python a fost ales ca limbaj de dezvoltare, dar acest lucru nu este deosebit de important. Modelele nu depind de un limbaj de programare specific și puteți transfera cu ușurință implementarea rezultată pe orice altă platformă.

Publicitate

Pe scurt despre modelul MVC

După cum sugerează și numele, modelul MVC include 3 componente: Model, View și Controller. Fiecare dintre componente își îndeplinește rolul și este interschimbabilă. Aceasta înseamnă că componentele sunt conectate între ele doar prin anumite interfețe clare, în spatele cărora poate sta orice implementare. Această abordare vă permite să înlocuiți și să combinați diverse componente, oferind logica de funcționare necesară sau aspectul aplicației. Să ne uităm la funcțiile pe care le îndeplinește fiecare componentă.

Model

Responsabil de logica internă a programului. Aici putem ascunde metodele de stocare a datelor, precum și regulile și algoritmii de prelucrare a informațiilor.

De exemplu, pentru o aplicație putem crea mai multe modele. Unul va fi depanat, iar celălalt va funcționa. Primul își poate stoca datele în memorie sau într-un fișier, iar al doilea folosește deja baza de date. În esență, acesta este doar un model de strategie.

Performanţă

Responsabil pentru afișarea datelor modelului. La acest nivel, oferim doar o interfață pentru interacțiunea utilizatorului cu Modelul. Scopul introducerii acestei componente este același ca și în cazul furnizării diferitelor modalități de stocare a datelor bazate pe mai multe Modele.

De exemplu, în primele etape de dezvoltare, putem crea o vizualizare simplă de consolă pentru aplicația noastră și abia apoi putem adăuga o interfață grafică frumos proiectată. Mai mult, rămâne posibilă salvarea ambelor tipuri de interfețe.

În plus, trebuie luat în considerare faptul că responsabilitățile Vizualizării includ doar afișarea în timp util a stării Modelului. Controlorul este responsabil pentru procesarea acțiunilor utilizatorului, despre care vom vorbi acum.

Controlor

Oferă o legătură între Model și acțiunile utilizatorului rezultate din interacțiunea cu vizualizarea. Coordonează momentele de actualizare a stărilor Modelului și Vederii. Ia cele mai multe decizii cu privire la tranzițiile aplicației de la o stare la alta.

De fapt, pentru fiecare acțiune pe care o poate face un utilizator într-o vizualizare, trebuie definit un handler în Controller. Acest handler va efectua manipulările corespunzătoare asupra modelului și, dacă este necesar, va notifica View că au existat modificări.

Publicitate

Specificațiile jocului de minere

Ajunge teorie. Acum să trecem la practică. Pentru a demonstra modelul MVC, vom scrie un joc simplu: Minesweeper. Regulile jocului sunt destul de simple:

  1. Terenul de joc este o zonă dreptunghiulară formată din celule. Unele celule au mine plasate aleatoriu în ele, dar jucătorul nu este conștient de ele;
  2. Jucătorul poate face clic pe orice celulă a terenului de joc cu butonul stânga sau dreapta al mouse-ului;
  3. Făcând clic pe butonul stâng al mouse-ului, celula va fi deschisă. Mai mult, dacă există o mină în celulă, atunci jocul se termină cu o pierdere. Dacă există mine în celulele adiacente lângă una deschisă, atunci pe celula deschisă va fi afișat un numărător cu numărul de mine din jur. Dacă nu există mine în jurul celulei deschise, atunci fiecare celulă învecinată va fi deschisă conform aceluiași principiu. Adică, celulele se vor deschide până când fie vor atinge limita terenului de joc, fie ajung la celulele deja deschise, fie nu există nicio mină lângă ele;
  4. Făcând clic pe butonul din dreapta al mouse-ului, vă permite să faceți semne pe celule. Făcând clic pe o celulă închisă, o marchează cu un steag, care îi blochează starea și previne deschiderea accidentală. Făcând clic pe o casetă marcată cu un steag, semnul acesteia se schimbă într-un semn de întrebare. În acest caz, celula nu mai este blocată și poate fi deschisă cu butonul stâng al mouse-ului. Făcând clic pe o celulă cu un semn de întrebare o readuce la starea sa închisă, nemarcată;
  5. Victoria este determinată de starea jocului în care toate celulele de pe terenul de joc sunt deschise, cu excepția celor minate.

Un exemplu de ceea ce vom obține este dat mai jos:

Diagramele UML ale jocului Minesweeper

Înainte de a trece la scrierea codului, ar fi o idee bună să vă gândiți în avans la arhitectura aplicației. Nu ar trebui să depindă de limbajul de implementare, așa că UML este cel mai bun pentru scopurile noastre.

Diagrama stării celulei de joc

Orice celulă de pe terenul de joc poate fi în una din cele 4 stări:

  1. Cușca este închisă;
  2. Cușca este deschisă;
  3. Celula este marcată cu un steag;
  4. Celula este marcată cu un semn de întrebare.

Aici am definit doar stările care sunt semnificative pentru Reprezentare. Deoarece mine nu sunt afișate în timpul jocului, starea corespunzătoare nu este furnizată în setul de bază. Să definim posibile tranziții de la o stare de celulă la alta folosind diagramele de stare UML:

Diagrama de clasă a jocului Minesweeper

Deoarece am decis să construim aplicația noastră pe baza modelului MVC, vom avea trei clase principale: MinesweeperModel, MinesweeperView și MinesweeperController, precum și o clasă de ajutor MinesweeperCell pentru a stoca starea celulei. Să ne uităm la diagrama lor de clasă:

Organizarea arhitecturii este destul de simplă. Aici am distribuit pur și simplu sarcini fiecărei clase în conformitate cu principiile modelului MVC:

  1. În partea de jos a ierarhiei se află clasa de celule de joc MinesweeperCell. Stochează poziția celulei, determinată de rândul rândului și coloana de coloană a terenului de joc; unul dintre statele pe care l-am descris în subsecțiunea precedentă; informații despre prezența unei mine într-o celulă (exploatată) și a unui contor de mine în celulele vecine. În plus, are două metode: nextMark() pentru parcurgerea stărilor asociate cu marcajele rezultate dintr-un clic dreapta și open() care gestionează evenimentul clic stânga;
  2. Chiar deasupra este clasa MinesweeperModel Model. El este containerul pentru celulele de joc MinesweeperCell. Prima sa metodă, startGame(), pregătește terenul de joc pentru a începe jocul. Metoda isWin() verifică câmpul de joc pentru o stare de câștig și returnează adevărat dacă jucătorul câștigă, în caz contrar, returnează false. O metodă similară este GameOver() este folosită pentru a verifica pierderea. Metodele openCell() și nextCellMark() pur și simplu delegă acțiuni celulelor corespunzătoare de pe terenul de joc, iar metoda getCell() returnează celula de joc solicitată;
  3. Clasa MinesweeperView View include următoarele metode: syncWithModel() - oferă redesenarea View pentru a afișa starea curentă a terenului de joc în Model; getGameSettings() - returnează setările jocului specificate de utilizator; createBoard() - creează un teren de joc pe baza datelor modelului; showWinMessage() și showGameOverMessage() afișează mesajele de câștig și, respectiv, de pierdere;
  4. Și în sfârșit clasa Controller MinesweeperController. Acesta definește doar trei metode pentru fiecare acțiune posibilă a jucătorului: startNewGame() este responsabil pentru a face clic pe butonul „Joc nou” din interfața Vizualizare; onLeftClick() și onRightClick() gestionează clicurile pe celulele jocului cu butoanele stânga și, respectiv, dreapta ale mouse-ului.

Implementarea jocului Minesweeper în Python

Este timpul să începem implementarea proiectului nostru. Să alegem Python ca limbaj de dezvoltare. Apoi vom scrie clasa View pe baza modulului tkinter.

Dar să începem cu Modelul.

Model MinsweeperModel

Implementarea Python a modelului arată astfel:

MIN_ROW_COUNT = 5 MAX_ROW_COUNT = 30 MIN_COLUMN_COUNT = 5 MAX_COLUMN_COUNT = 30 MIN_MINE_COUNT = 1 MAX_MINE_COUNT = 800 Class MinesweeperCell: # Stări posibile ale celulei jocului: # închis - închis - închis # steag deschis - steag cu întrebare - deschis # steag interogat __init__(self , row, column): self.row = row self.column = coloana self.state = „închis” self.mined = False self.counter = 0 markSequence = [ „închis”, „marcat”, „întrebat” ] def nextMark (self): dacă self.state în 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 = "deschis" clasa MinesweeperModel: def __init__(self): self.startGame() def startGame(self, rowCount = 15, columnCount = 15, mineCount = 15): dacă rowCount în interval (MIN_ROW_COUNT, MAX_ROW_COUNT + 1): self.rowCount = rowCount dacă columnCount în interval (MIN_COLUMN_COUNT, MAX_COLUMN_COUNT + 1): self.columnCount = columnCount dacă 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 partea de sus definim gama de setări de joc acceptabile:

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 general, aceste setări pot fi incluse și în Model. Cu toate acestea, dimensiunea câmpului și numărul de mine sunt informații destul de statice și este puțin probabil să se schimbe frecvent.

Apoi am definit clasa de celule de joc MinesweeperCell. S-a dovedit a fi destul de simplu. În constructorul de clasă, câmpurile de celule sunt inițializate la valorile implicite. În continuare, pentru a simplifica implementarea tranzițiilor ciclice de stare, folosim lista auxiliară markSequence. Dacă celula se află în starea „deschisă”, care nu este inclusă în această listă, atunci nu se va întâmpla nimic în metoda nextMark(), altfel celula trece în starea următoare, iar din ultima stare „întrebatată” „sare” „la starea inițială „închisă””. În metoda open(), verificăm starea celulei, iar dacă nu este „marcată”, atunci celula intră în starea deschisă „deschisă”.

Urmează definiția clasei MinesweeperModel Model. Metoda startGame() dispune terenul de joc folosind parametrii rowCount, columnCount și mineCount care îi sunt transmise. Fiecare parametru este verificat pentru a vedea dacă se află în intervalul acceptabil de valori. Dacă valoarea transmisă este în afara intervalului, atunci valoarea parametrului câmpului de joc este salvată și nu se modifică. Trebuie remarcat faptul că există o verificare suplimentară pentru numărul de mine. Dacă numărul de mine transferat depășește dimensiunea câmpului, atunci îl limităm la numărul de celule fără unitate. Deși, bineînțeles, un astfel de joc nu are prea mult sens și va fi finalizat într-un singur pas, așa că puteți veni cu unele dintre propriile reguli pentru un astfel de caz.

Terenul de joc este stocat ca o listă de liste de celule din variabila cellsTable. Mai mult, rețineți că în metoda startGame() este setată doar valoarea de poziție a celulelor, dar minele nu sunt încă plasate. Dar variabila firstStep este definită cu valoarea True . Acest lucru este necesar pentru a elimina elementul de șansă de la prima mișcare și pentru a preveni pierderea instantanee. Minele vor fi plasate după prima mișcare în celulele rămase.

Metoda getCell() returnează pur și simplu celula câmpului de joc după rând rând și coloană. Dacă valoarea rândului sau a coloanei este invalidă, atunci se returnează Niciunul.

Metoda isWin() returnează True dacă toate celulele rămase nedeschise ale terenului de joc sunt minate, adică în caz de victorie, altfel va returna False. Metoda isGameOver() returnează pur și simplu valoarea atributului clasei gameOver.

Metoda openCell() deleagă apelul open() obiectului celulă de joc, care se află pe terenul de joc la poziția specificată în parametrii metodei. Dacă celula deschisă se dovedește a fi extrasă, atunci setăm valoarea gameOver la True și ieșim din metodă. Dacă jocul nu s-a încheiat încă, atunci ne uităm să vedem dacă aceasta este prima mișcare verificând valoarea firstStep . Dacă este într-adevăr prima mișcare, atunci mine vor fi plasate pe terenul de joc folosind metoda auxiliară generateMines(), despre care vom vorbi puțin mai târziu. Apoi, numărăm numărul de celule învecinate extrase și setăm valoarea corespunzătoare a atributului contor pentru celula care este procesată. Dacă contorul este zero, atunci solicităm o listă de celule învecinate folosind metoda getCellNeighbours() și apelăm recursiv metoda openCell() pentru toți „vecinile” închise, adică pentru celulele cu starea „închisă”.

Metoda nextCellMark() delegă pur și simplu apelul la metoda nextMark() pentru celula situată la poziția trecută.

Amplasarea minelor are loc în metoda generateMines(). Aici pur și simplu selectăm aleatoriu o poziție pe terenul de joc și verificăm dacă celula din această poziție nu este deschisă și nu a fost deja extrasă. Dacă ambele condiții sunt îndeplinite, atunci setăm valoarea atributului minat la True, în caz contrar, continuăm să căutăm o altă celulă liberă. Nu uitați că, pentru a utiliza modulul aleatoriu în Python, trebuie să îl importați în mod explicit cu comanda import random.

Metoda countMinesAroundCell() pentru numărarea numărului de mine din jurul unei anumite celule a terenului de joc se bazează în întregime pe metoda getCellNeighbours(). Solicitarea „vecinilor” unei celule în metoda getCellNeighbours() este, de asemenea, implementată extrem de simplu. Nu cred că vei avea probleme cu el.

MinesweeperView

Acum să trecem la spectacol. Codul Python pentru clasa MinesweeperView este mai jos:

Clasa MinesweeperView(Frame): def __init__(self, model, controller, parent = None): Frame.__init__(self, parent) self.model = model self.controller = controller self.controller.setView(self) self.createBoard( ) panel = Frame(self) panel.pack(side = BOTTOM, fill = X) Button(panou, text = "New Game", comandă = self.controller.startNewGame).pack(side = RIGHT) self.mineCount = StringVar (panou) self.mineCount.set(self.model.mineCount) Spinbox(panoul, de la_ = MIN_MINE_COUNT, până la = MAX_MINE_COUNT, textvariable = self.mineCount, lățime = 5).pack(side = RIGHT) Label(panou, text = " Numărul de minute: ").pack(side = RIGHT) self.rowCount = StringVar(panel) self.rowCount.set(self.model.rowCount) Spinbox(panel, from_ = MIN_ROW_COUNT, to = MAX_ROW_COUNT, textvariable = self. rowCount , lățime = 5).pack(side = RIGHT) Label(panel, text = " x ").pack(side = RIGHT) self.columnCount = StringVar(panel) self.columnCount.set(self.model.columnCount) Spinbox (panou, de la_ = MIN_COLUMN_COUNT, până la = MAX_COLUMN_COUNT, textvariable = self.columnCount, lățime = 5).pack(side = RIGHT) Label(panel, text = "Dimensiunea câmpului: ").pack(side = RIGHT) def syncWithModel (self): pentru rândul din interval(self.model.rowCount): pentru coloana din interval(self.model.columnCount): cell = self.model.getCell(row, column) if cell: btn = self.buttonsTable[ row ] [ coloană ] dacă self.model.isGameOver() și cell.mined: btn.config(bg = "negru", text = "") dacă cell.state == "închis": btn.config(text = "" ) elif cell.state == "deschis": btn.config(relief = SUNKEN, text = "") if cell.counter > 0: btn.config(text = cell.counter) elif cell.mined: btn.config( bg = „roșu”) elif cell.state == „marcat”: btn.config(text = „P”) elif cell.state == „întrebat”: btn.config(text = „?”) def blockCell(self , rând, coloană, bloc = Adevărat): btn = self.buttonsTable[ rând ][ coloană ] dacă nu btn: returnează dacă bloc: btn.bind(" ", "break") else: btn.unbind(" ") def getGameSettings(self): return self.rowCount.get(), self.columnCount.get(), self.mineCount.get() def createBoard(self): încercați: 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) cu excepția: trece self.board = Frame(self ) self.board.pack() self.buttonsTable = pentru rândul din interval(self.model.rowCount): line = Frame(self.board) line.pack(side = TOP) self.buttonsRow = pentru coloana din interval(self .model.columnCount): btn = Button(linie, lățime = 2, înălțime = 1, comandă = lambda rând = rând, coloană = coloană: self.controller.onLeftClick (rând, coloană), padx = 0, pady = 0) btn.pack(partea = STÂNGA) btn.bind(" ", lambda e, row = row, column = column: self.controller.onRightClick(row, column)) self.buttonsRow.append(btn) self.buttonsTable.append(self.buttonsRow) def showWinMessage(self): showinfo( „Felicitări!”, „Câștigi!”) def showGameOverMessage(self): showinfo(„Game over!”, „Pierzi!”)

Vizualizarea noastră se bazează pe clasa Frame din modulul tkinter, deci asigurați-vă că executați comanda de import adecvată: from tkinter import * . Constructorul clasei trece Modelul și Controlerul. Metoda createBoard() este apelată imediat pentru a aranja terenul de joc din celule. Permiteți-mi să spun în avans că în acest scop vom folosi butoanele obișnuite Button. Apoi este creat un cadru, care va acționa ca un panou de jos pentru specificarea parametrilor jocului. Pe acest panou plasăm secvențial butonul „Joc nou”, al cărui handler este controlerul nostru cu metoda startNewGame(), și apoi trei contoare Spinbox, astfel încât jucătorul să poată specifica dimensiunea terenului de joc și numărul de mine.

Metoda syncWithModel() trece pur și simplu de două ori prin fiecare celulă de joc și schimbă în consecință aspectul butonului care îl reprezintă în GUI. Pentru simplitate, am folosit simboluri de text pentru a afișa notația, dar nu este atât de dificil să schimbi textul în grafică din fișierele grafice externe.

De asemenea, rețineți că folosim stilul butonului SUNKEN pentru a reprezenta o celulă deschisă. Și în caz de pierdere, deschidem locația tuturor minelor de pe terenul de joc, arătând butoanele corespunzătoare în negru, și evidențiem butonul corespunzător ultimei celule deschise cu o mină în roșu:

Următoarea metodă blockCell() are un rol de sprijin și permite controlerului să seteze starea de blocare a butoanelor. Acest lucru este pentru a preveni deschiderea accidentală a celulelor de joc marcate și se realizează prin setarea unui handler de clic stânga gol.

Metoda getGameSettings() returnează pur și simplu valorile contoarelor situate în panoul de jos cu dimensiunea terenului de joc și numărul de mine.

Crearea unei reprezentări a terenului de joc se face în metoda createBoard(). În primul rând, încercăm să ștergem vechiul teren de joc, dacă a existat și, de asemenea, încercăm să setăm valorile contorului din panou în conformitate cu configurația actuală a Modelului. Se creează apoi un nou Frame, pe care îl vom numi tablă, pentru a reprezenta terenul de joc. Compunem tabelul de butoane Tabel după același principiu ca și celulele de joc din Model folosind o buclă dublă. Managerii fiecărui buton sunt legați de metodele onLeftClick() și onRightClick() ale Controllerului pentru a face clic pe butoanele stânga și, respectiv, dreapta ale mouse-ului.

Ultimele două metode showWinMessage() și showGameOverMessage() afișează pur și simplu casete de dialog cu mesajele corespunzătoare folosind funcția showinfo(). Pentru a-l utiliza, va trebui să importați încă un modul: din tkinter.messagebox import * .

Controller MinesweeperController

Acum am ajuns la implementarea Controllerului:

Clasa MinesweeperController: def __init__(self, model): self.model = model def setView(self, view): self.view = view def startNewGame(self): gameSettings = self.view.getGameSettings() try: self.model. startGame(*map(int, gameSettings)) cu excepția: self.model.startGame(self.model.rowCount, self.model.columnCount, self.model.mineCount) self.view.createBoard() def onLeftClick(self, row, coloană): self.model.openCell(rând, coloană) self.view.syncWithModel() dacă self.model.isWin(): self.view.showWinMessage() self.startNewGame() elif self.model.isGameOver(): self.view.showGameOverMessage() self.startNewGame() def onRightClick(self, row, column): self.model.nextCellMark(rând, coloană) self.view.blockCell(rând, coloană, self.model.getCell(rând, column).state == „marcat”) self.view.syncWithModel()

Pentru a lega View la Controller, am adăugat metoda setView(). Acest lucru se datorează faptului că, dacă am dori să transmitem o vizualizare constructorului, atunci această vizualizare ar trebui să existe deja înainte ca controlerul să fie creat. Și apoi o soluție similară cu o metodă suplimentară de legare s-ar muta pur și simplu de la Controller la View, în care ar apărea metoda setController().

Metoda de gestionare pentru a face clic pe butonul Joc nou, startNewGame(), solicită mai întâi parametrii jocului introduși în vizualizare. Parametrii jocului sunt returnați ca un tuplu de trei componente, pe care încercăm să le convertim în int . Dacă totul merge bine, atunci trecem aceste valori metodei modelului startGame() pentru a construi terenul de joc. Dacă ceva nu merge bine, pur și simplu vom recrea terenul de joc cu vechii parametri. În cele din urmă, facem o solicitare de a crea o nouă afișare a tablei de joc în View apelând metoda createBoard().

Managerul onLeftClick() îi spune mai întâi modelului să deschidă celula de joc în poziția aleasă de jucător. Apoi informează View că starea Modelului s-a schimbat și se oferă să redeseneze totul. Apoi Modelul este verificat pentru victorie sau pierdere. Dacă se întâmplă oricare dintre acestea, mai întâi este trimisă o solicitare către View pentru a afișa notificarea corespunzătoare, iar apoi handlerul startNewGame() este apelat pentru a începe un joc nou.

Clic-dreapta este gestionat în metoda onRightClick(). Prima linie apelează metoda nextCellMark() a modelului pentru a schimba ciclic marcajul celulei de joc selectate. În funcție de noua stare a celulei, se trimite o solicitare către View pentru a seta sau a elimina blocarea butonului corespunzător. Și la sfârșit, vizualizarea este din nou actualizată pentru a afișa starea curentă a modelului.

Combinând model, vizualizare și controler

Acum, tot ce rămâne este să conectăm toate elementele din implementarea noastră a Minesweeper pe baza modelului MVC și să lansăm jocul:

Model = MinesweeperModel() controller = MinesweeperController(model); vizualizare = MinesweeperView(model, controler) view.pack() view.mainloop()

Concluzie

Așa că ne-am uitat la modelul MVC. Să trecem pe scurt prin teorie. Și apoi am creat o aplicație de jocuri cu drepturi depline, pas cu pas, mergând de la declararea problemei și proiectarea arhitecturii la implementarea în limbajul de programare Python folosind modulul grafic tkinter.

Model Model-View-Controller (MVC), descoperit la sfârșitul anilor 1970, este un model de proiectare a arhitecturii software al cărui scop principal este separarea funcțiilor datelor de prezentarea datelor. Teoretic, o aplicație MVC bine concepută va permite dezvoltatorilor front-end și back-end să nu interfereze cu domeniile de responsabilitate ale celuilalt în timpul muncii lor, adică dezvoltatorul front-end nu va trebui să știe nimic despre „bucătărie” a colegului său de back-end și invers.

Deși MVC a fost conceput inițial pentru dezvoltarea aplicațiilor desktop, a fost adaptat pentru sarcini moderne și este extrem de popular în rândul dezvoltatorilor web, deoarece face posibilă crearea unui cod mai curat și mai reutilizabil prin separarea responsabilităților. Modelul MVC are ca rezultat sisteme curate, modulare, care permit dezvoltatorilor să facă modificări la codul existent foarte rapid.

În acest articol, ne vom uita la principiile de bază ale MVC, începând cu definirea unui model și continuând cu aplicarea acestuia într-un mic exemplu. Acest articol va fi util în primul rând celor care nu au întâlnit niciodată acest tipar în viață și, poate, de asemenea, celor care doresc să-și perfecționeze cunoștințele despre MVC.

Înțelegerea MVC

După cum am menționat deja, numele modelului provine dintr-o abreviere a trei cuvinte: Model (model), VedereȘi Controlor. Pe scurt, principiul de funcționare al modelului poate fi ilustrat cu o diagramă (poate fi găsită pe Wikipedia):

Această diagramă arată clar fluxul unidirecțional de informații în model și, de asemenea, descrie rolurile fiecărei componente.

Model

Modelul este folosit pentru a accesa și manipula date. În cele mai multe cazuri, modelul este ceea ce este folosit pentru a accesa depozitul de date (cum ar fi o bază de date). Modelul oferă o interfață pentru căutarea datelor, crearea, modificarea și ștergerea lor din stocare. În contextul modelului MVC, modelul este mediatorul între vedere și controler.

O caracteristică extrem de importantă a unui model este că, din punct de vedere tehnic, nu cunoaște ceea ce se întâmplă cu datele din controlor și vizualizare. Modelul nu ar trebui să facă sau să aștepte niciodată solicitări către/de la alte componente ale modelului.

Cu toate acestea, amintiți-vă întotdeauna că modelul nu este doar o poartă către o bază de date sau alt sistem care nu face altceva decât să transfere date înainte și înapoi. Un model este ca o poartă către date. Modelul este în majoritatea cazurilor cea mai complexă parte a sistemului, parțial datorită faptului că modelul în sine este veriga de legătură pentru toate celelalte părți.

Performanţă

Vizualizarea este locul în care datele primite de la model sunt afișate în forma dorită. În aplicațiile web tradiționale dezvoltate folosind modelul MVC, vizualizarea este partea din sistem în care este generat codul HTML. Vizualizarea este, de asemenea, responsabilă pentru primirea acțiunilor de la utilizator pentru a le trimite controlorului. De exemplu, o vizualizare redă un buton în interfața de utilizare și, atunci când este făcută clic, invocă acțiunea controlerului corespunzătoare.

Există unele concepții greșite cu privire la scopul unei vizualizări, în special în rândul dezvoltatorilor web care abia încep să-și construiască aplicațiile folosind MVC. Una dintre regulile cele mai des încălcate este aceea vederea nu ar trebui să comunice în niciun fel cu modelul, si tot datele primite de vizualizare ar trebui să provină numai de la operator. În practică, dezvoltatorii ignoră adesea acest concept, care se află la baza modelului MVC. Articolul lui Fabio Cevasco ilustrează această abordare confuză a MVC folosind CakePHP, unul dintre multele cadre MVC non-standard:

Este extrem de important să înțelegeți că, pentru a obține o arhitectură MVC adecvată, nu ar trebui să existe interacțiuni directe între vederi și modele. Toată logica pentru schimbul de date între ele trebuie implementată în controlere.

În plus, există o concepție greșită comună că o vizualizare este doar un fișier șablon. După cum a menționat Tom Butler, această concepție greșită este uriașă datorită faptului că mulți dezvoltatori înțeleg greșit structura MVC de la bun început, după care încep să reverse această „cunoaștere” mai mult în masele de dezvoltatori începători. În realitate, o vedere este mult mai mult decât un șablon, dar multe cadre construite pe deasupra modelului MVC au distorsionat atât de mult conceptul de vedere încât nimănui nu-i pasă dacă aplicațiile lor sunt corecte în ceea ce privește modelul MVC.

Un alt punct important este că vizualizarea nu funcționează niciodată cu date „pure” de la controler, adică controlerul nu funcționează niciodată cu vizualizarea fără a ocoli modelul. În timpul interacțiunii dintre controler și vizualizare, modelul ar trebui să fie întotdeauna între ele.

Controlor

Controlerul este ultima parte a pachetului MVC. Sarcina controlorului este să primească date de la utilizator și să manipuleze modelul. Controlerul și numai acesta este partea sistemului care interacționează cu utilizatorul.

Pe scurt, un controler poate fi descris ca un colector de informații care le transmite modelului pentru procesare și stocare. Nu ar trebui să facă nimic cu datele, ci doar să le poată primi de la utilizator. Controlerul este asociat cu o vedere și un model, organizând astfel un flux unidirecțional de date, controlându-l în fiecare etapă.

Este foarte important să ne amintim că controlerul își începe activitatea doar ca urmare a interacțiunii utilizatorului cu vizualizarea, care apelează funcția de controler corespunzătoare. Cea mai frecventă greșeală în rândul dezvoltatorilor este de a vedea controlerul ca pur și simplu o poartă de acces între vizualizare și model. Ca urmare, controlerul este dotat cu acele funcții care ar trebui să fie efectuate de vizualizare (apropo, de aici vine ideea că o vizualizare este doar un fișier șablon). În plus, mulți oameni aruncă complet toată logica de procesare a datelor, uitând de ce este destinat modelul în modelul MVC.

MVC în PHP

Vă sugerez să încercați să implementați cele de mai sus într-o aplicație mică. Să începem prin a crea clasele model, vizualizare și controler:

șir = „MVC + PHP = Minunat!”; ) )controler = $controller; $acest->

" . $this->model->string ."

"; } } model = $model; ) )

Clasele principale sunt gata. Acum să le conectăm împreună și să rulăm aplicația noastră:

ieșire();

După cum puteți vedea, controlerul nu are nicio funcționalitate, deoarece utilizatorul nu interacționează cu aplicația în niciun fel. Toate funcționalitățile sunt plasate în vizualizare, deoarece aplicația noastră este destinată exclusiv pentru afișarea datelor.

Să extindem puțin aplicația adăugând ceva interactivitate pentru a vedea cum funcționează controlerul:

șir = „MVC + PHP = Minunat, dați clic aici!”; ) )controler = $controller; $acest->model = $model; ) funcția publică output() ( return "

model->șir . "

"; } } model = $model; ) funcția publică a făcut clic () ( $this->model->string = „Date actualizate, mulțumim MVC și PHP!”) )

Și, în sfârșit, să modernizăm ușor codul de conectare:

($_GET[„acțiune”])(); ) echo $view->output();

Rezultate

În acest scurt articol, ne-am uitat la conceptele de bază ale modelului de design MVC și am dezvoltat o aplicație simplă bazată pe acesta, deși, desigur, suntem încă departe de a-l folosi în viața reală. În articolul următor, vom analiza principalele dificultăți pe care le veți întâmpina dacă vă implicați mai mult în construirea unei arhitecturi de aplicație bazată pe modelul MVC. Rămâneţi aproape!

Dezvoltarea unei aplicații conform modelului de design MVC (Model-View-Controller) este tipică pentru Java și pare confuză și inutilă atunci când este aplicată la DroidScript. De ce sa complici totul? MVC a dobândit o aură de complexitate și „magie” datorită utilizării de cuvinte frumoase, dar de neînțeles (concept, model, logica de afaceri, model) și demonstrații complexe în contextul Java atunci când îl luam în considerare. Totul este mult mai simplu: MVC este unul dintre modelele de design care produce adiţionaldistribuie codulîn orientat obiect mediu inconjurator.

Elementul central al modelului MVC este controlerul - o aplicație obișnuită DroidScript, din care este scos codul legat de marcajul vizual și aspectul widget-urilor, precum și datele și metodele de accesare a acestora. Prin date suntem obișnuiți să înțelegem informațiile stocate în matrice, fișiere și baze de date. Dar în conceptul MVC, datele sunt înțelese în sensul larg al cuvântului - acesta este tot ceea ce nu este cod de aplicație:

  • date externe din fișiere și baze de date - metadate, text, grafică, sunete, muzică etc.
  • date interne aplicației - linii cu etichete pe butoane și alte comenzi, text în casete de dialog, descrieri ale stilurilor, constante, grafice generate de software etc.

Din punctul de vedere al utilizatorului, experiența lui cu aplicația nu se schimbă atunci când folosește MVC: de asemenea, dă clic pe butoane, selectează datele și cum sunt afișate. Modificările pot preocupa facilităţi acest lucru. Iar pe partea de dezvoltare, schimbările sunt vizibile: interacțiunea dintre date și afișarea acestora în conceptul MVC are loc prin controlor și sub controlul acestuia.

Să ne uităm mai întâi la un exemplu simplu de utilizare a MVC într-o aplicație cu un singur fișier.

Implementarea într-un singur fișier a modelului MVC

Să luăm o aplicație simplă.

Funcția OnStart())( var _lay = app.CreateLayout("liniar", "VCenter,FillXY"); var _btnShowVersion = app.CreateButton ("Afișați versiunea", 0.3, 0.1); _btnShowVersion.SetBackColor("#66778("#6676") _btnShowVersion.SetMargins(0, 0.05, 0, 0); _btnShowVersion.SetOnTouch(function())( _btnShowVersion.SetText("Versiunea aplicației 1.0");

La prima vedere, totul pare în regulă, dar să presupunem că trebuie să schimbați schema de culori a aplicației și să afișați textul în mai multe limbi. Acest lucru va duce la complicații, deoarece toate datele din exemplul prezentat sunt valori fixe (literale). Acest lucru reduce semnificativ flexibilitatea codului și complică depanarea și suportul acestuia.

Un alt dezavantaj este că datele - etichetele de pe buton, marcajul - metodele de afișare a widget-urilor și acțiunea - blocul de cod care schimbă eticheta butonului atunci când este apăsat se află într-un singur bloc și într-un singur fișier. Adică, pentru a schimba eticheta, trebuie să deschideți acest fișier și să obțineți acces la întregul cod al aplicației. Este ca și cum schimbarea unei anvelope de mașină necesită dezasamblarea caroseriei mașinii pentru a avea acces la tot conținutul. Pentru ce? În timpul procesului de dezasamblare a caroseriei mașinii, puteți prinde ceva accidental și îl puteți face inoperant. Este posibil și în cod: am vrut să înlocuiesc numele liniei într-un singur loc, dar înlocuirea a avut loc în întregul fișier, ceea ce a dus la o împrăștiere a erorilor. Sau ați vrut doar să schimbați culoarea butonului, dar ați prins accidental codul în apropiere și întreaga aplicație a încetat să funcționeze.

Una dintre sarcinile modelului MVC este tocmai de a diferenția accesul: mai întâi, modulul (sau blocul de cod) care este sursa erorii este identificat, iar apoi accesul este acordat numai acestuia. De ce să dai acces la electronicele și la motorul unei mașini dacă trebuie să schimbi o anvelopă?

Dacă dezvoltarea se realizează într-un singur fișier, atunci acest lucru se întâmplă adesea astfel: noi funcții sunt plasate la locul lor, chiar la începutul sau la sfârșitul codului, ceea ce în timp duce la amestecarea lor. Să adăugăm aici amestecul de cod în funcțiile în sine, iar într-o lună, chiar și cu comentarii, va fi greu de înțeles toate acestea.

Să implementăm exemplul prezentat mai sus în contextul MVC. Pentru a face acest lucru, tot codul trebuie să fie împărțit și grupat în blocuri adecvate. Ordinea blocurilor din cod nu este importantă, dar este mai bine să respectați logica: pentru ca controlerul să funcționeze, sunt necesare atât datele, cât și elementele pentru afișarea lor, deci este plasat pe ultimul loc. Când datele sunt afișate, acestea trebuie să existe. Aceasta înseamnă că blocul model este pe primul loc:

  1. Model
  2. Performanţă
  3. Controlor
//+++ model (function())( var _obj = ; //+++ date var _version = „Versiunea aplicației 1.0”; var _titleShowVersion = „Afișați versiunea”; //--- date
//+++ metode publice pentru accesarea datelor _obj.getVersion = function())( return _version; ) _obj.btnGetTitle = function())( return _titleShowVersion; ) //--- metode publice pentru accesarea datelor window.model = _obj; // deschideți accesul la obiectul local ))(); //--- model //+++ prezentare (funcție ()( var _lay = app.CreateLayout("liniar", "VCenter,FillXY"); var _btnShowVersion = app.CreateButton(window.model.btnGetTitle(), 0.3, 0.1); _btnShowVersion.name = "_btnShowVersion.SetBackColor("#66778976");

))(); //--- prezentare //+++ controller (function(p_object)( var _obj = ; // metoda de căutare a obiectelor publice _obj.findObjectById = function(p_name)( var _objectList = app.GetObjects(); for (var _i în _objectList)( if(_objectList[_i].name == p_name)( return _objectList[ _i]; ) ) return null window.control = _obj))(); funcția OnStart())( var _buttonShowVersion = window.control.findObjectById("_btnShowVersion"); //+++ acțiune _buttonShowVersion.SetOnTouch(function())( this.SetText(window.model.getVersion()); )) ; / / --- acțiune ) //--- controler

Datorită separării funcțiilor, codul aplicației a crescut de mai multe ori.

Inițial, toate variabilele sunt private și abia la sfârșit, dacă este necesar, accesul la ele se face prin obiectul fereastră globală, care vă permite să faceți fără variabile globale.

Exemplul implementează o căutare prin widget, ca în Java, dar o puteți face mai simplu și face codul mai eficient prin deschiderea accesului la obiect printr-o matrice asociativă globală:

Window.controls = ;
window.controls.buttonShowVersion = _btnShowVersion;

Datele, afișarea lor și reacția la acțiuni sunt situate în blocuri diferite, fără a se amesteca între ele, ceea ce permite dezvoltatorului să lucreze cu ele mai ușor. Cu cât este mai ușor să lucrați cu date și cod, cu cât vor fi mai puține erori, cu atât va fi mai ușor de depanat, suportat și scalat.

Nu este necesar să se separe toate aceste trei componente unele de altele. Există mai multe variații ale MVC, precum și implementări incomplete ale acestui model. De exemplu, puteți separa datele și puteți combina codul de acțiune cu controalele folosind funcții de apel invers anonim.

Când se lucrează într-un mediu orientat pe obiecte, separarea codului și datelor este deja prezentă de la bun început: datele și acțiunile sunt grupate în clase, obiectele interacționează între ele prin metode publice etc. MVC permite o separare mai fină și mai explicită a codului și datelor în funcțiile lor de bază.

Pentru a înțelege mai bine beneficiile utilizării modelului MVC, să ne uităm la împărțirea codului în fișiere separate.

Implementarea în trei fișiere a modelului MVC

Separarea codului în fișiere diferite este folosită pentru a face lucrul cu acesta mai convenabil. Numărul imens de fișiere mici care pot fi văzute în proiectele MVC poate pune această afirmație sub semnul întrebării, dar a vedea fișierele este una, dar lucrul cu ele este altceva. În fiecare moment, dezvoltatorul interacționează cu un fișier dintr-un set mic de ele. Pentru a face acest lucru, trebuie să înțelegeți bine structura de organizare a proiectului și să monitorizați în mod constant trei dosare- model, vizualizare și controler, pentru a nu edita accidental codul terților. Din cauza limitărilor editorului DroidScript, o astfel de grupare este posibilă numai după numele fișierelor din directorul rădăcină, de exemplu:

myproject_model.js - model
myproject_view.js - vizualizare
myproject_control.js - controler

Mai jos este un exemplu de împărțire a codului exemplului anterior în fișiere.

myproject_model.js - model(function())( var _obj = ; //+++ data var _version = „Versiunea aplicației 1.0”; //--- data //+++ resursă șir var _titleShowVersion = „Afișează versiunea”; //++ + resursă șir _obj.getVersion = function() ( return _version; ) _obj.btnGetTitle = function() ( return _titleShowVersion; ) window.model = _obj ))(); myproject_view.js - vizualizare(funcție ()( var _lay = app.CreateLayout("liniar", "VCenter,FillXY"); var _btnShowVersion = app.CreateButton(window.model.btnGetTitle(), 0.3, 0.1); _btnShowVersion"tnS = "_btnShowVersion"tnS = "__ _btnShowVersion.SetBackColor("#66778976"); _btnShowVersion.SetMargins(0, 0.05, 0, _lay.AddChild(_btnShowVersion(_lay)); myproject_control.js - controler app.LoadScript("myproject_model.js"); app.LoadScript ("myproject_view.js");(function(p_object)( var _obj = ; // metoda de căutare a obiectelor _obj.findObjectById = function(p_name)( var _objectList = app.GetObjects(); for (var _i in _objectList)( if(_objectList[_i].name = = p_name)( return _objectList[ _i]; ) ) return null.control = _obj; funcția OnStart())( var _buttonShowVersion = window.control.findObjectById("_btnShowVersion"); //+++ acțiune _buttonShowVersion.SetOnTouch(function())( this.SetText(window.model.getVersion()); )) ; / / --- acțiune )

Această simplă împărțire a codului în fișiere nu a fost ușoară. Pentru a face acest lucru, a fost stabilită în prealabil o conexiune cu modelul prin proprietatea publică a obiectului rădăcină globală - fereastră.model, iar conexiunea cu vizualizarea se face printr-o matrice globală _Hartă prin metoda app.GetObjects.

Avantajul împărțirii codului în fișiere este că acum puteți înlocui codul ca un întreg bloc, de exemplu, pentru a începe rapid un proiect, implementați un model simplu și apoi înlocuiți fișierul cu altul mai funcțional, dar cu același nume și interfață. Această abordare este utilizată, de exemplu, la repararea echipamentelor. Dacă reparațiile anterioare constau în căutarea și înlocuirea lentă și minuțioasă a componentelor radio defectuoase, acum unitățile standard sunt înlocuite. Costul reparației unei plăci complexe este semnificativ mai mare decât înlocuirea sa rapidă.

Din cele de mai sus rezultă că o interfață bine concepută poate simplifica semnificativ integrarea ulterioară a modulelor.

În JavaScript, obiectele sunt transmise prin referință. Modificarea proprietăților widgetului în controler va schimba proprietățile se widget. Teoretic, este posibil să se separe obiectele de vizualizare de obiectele de cod, așa cum se face în Java, unde structurile xml sunt folosite ca primele, dar acest lucru nu are prea mult sens din două motive - lipsa unui editor de interfață vizuală în DroidScript și un set limitat de proprietăți disponibile ale obiectelor API.

Implementarea în mai multe fișiere a modelului MVC

În funcție de sarcinile atribuite și de complexitatea proiectului, detaliile separării codului și datelor, în general, pot fi diferite. Puteți separa în continuare datele utilizatorului de resurse, puteți detalia resursele după tip, acțiuni de grup etc. Dar editorul DroidScript nu vă permite să lucrați pe deplin funcțional folosind MVC.

Valoare nominală 5000 de ruble

Număr (gs 8225497)

Imitația unei bancnote veritabile a Băncii Rusiei, model 1997.

Hârtie. Nu are fluorescență în razele UV

Metoda de imprimare. Imprimare offset plat - toate imaginile. Reproducerea culorilor este distorsionată. Toate imaginile au o strălucire caracteristică. Format din puncte colorate. În locurile îndoite, se observă scurgerea vopselei.

SEMNELE PUBLICE DE PROTECȚIE. PARTEA FRONTALĂ

Filigrane (1,2)


Imitată de o supraimprimare cu o substanță albă pe față. Imaginile filigrane distorsionate sunt vizualizate în lumină reflectată

Imagine latentă (efect kipp)(3)


Nu este reprodus

Fibre de securitate

Imitată prin supratipărire. În razele UV există o strălucire în culorile verde și roșu.

Vopsea cu culori variabile (4)


Imaginea stemei a sporit strălucirea. Efectul OVI nu este reprodus

Element MVC+(5).


Nu imitat. Franjurile Moire ale efectului MVC sunt observate la orice unghi de vizualizare; a apărut în timpul copierii de pe original.

Microperforare(6)


Imitat. Găurile microperforate sunt vizibile în lumina reflectată

Lac cu culori variabile (7)

Emblema Băncii Rusiei este acoperită cu vopsea aurie. Efectul de polarizare nu este reprodus.

embosare incoloră (8)

Nu imitat

Relief

Nu imitat

Valoare nominală 5000 de ruble

Număr (gs 8225497)

Imitația unei bancnote autentice de la Banca Rusiei din 1997.

SEMNELE PUBLICE DE PROTECȚIE. PARTE POST

Microtexte(9,10)


Reproduce parțial

Fir de securitate(11)


Imitate cu o substanță albă pe față, ieșirile sunt imitate cu ștanțare în folie. Ieșirile firului de securitate sunt abia vizibile.

CARACTERISTICI DE SECURITATE CITEBILE LA MAȘINĂ

Protectie luminescenta

Parțial imitat

protectie IR

Parțial imitat

Protectie magnetica

Nu imitat

Notă. Potrivit agențiilor ruse de aplicare a legii, o bancnotă contrafăcută a fost confiscată în regiunea Perm.

Material pregătit IPK „InterCrim-press”.

Cele mai bune articole pe această temă