Fațada la distanță. Model de design de fațadă în PHP Discuție despre modelul de fațadă

Citiți descrierile altor modele.

Problemă

Minimizați dependența subsistemelor unui sistem complex și schimbul de informații între ele.

Descriere

La proiectarea sistemelor complexe, așa-numitele principiul descompunerii, în care un sistem complex este defalcat în subsisteme mai mici și mai simple. Mai mult, nivelul de descompunere (adâncimea acestuia) este determinat exclusiv de proiectant. Datorită acestei abordări, componentele individuale ale sistemului pot fi dezvoltate izolat și apoi integrate împreună. Cu toate acestea, apare o problemă care este evidentă la prima vedere - conectivitatea ridicată a modulelor de sistem. Acest lucru se manifestă, în primul rând, în cantitatea mare de informații pe care modulele le schimbă între ele. În plus, pentru o astfel de comunicare, unele module trebuie să aibă suficiente informații despre natura altor module.

Astfel, reducerea la minimum a dependenței subsistemelor, precum și reducerea cantității de informații transmise între ele, este una dintre principalele sarcini de proiectare.

O modalitate de a rezolva această problemă este utilizarea modelului „Fațadă”.

Modelul Façade oferă o interfață unificată în loc de un set de interfețe de subsistem. O fațadă definește o interfață de nivel superior care
Acest lucru simplifică utilizarea subsistemului.

Pur și simplu, o „fațadă” nu este altceva decât un obiect care acumulează un set de operațiuni de nivel înalt pentru lucrul cu un subsistem complex. Fațada agregează clasele care implementează funcționalitatea acestui subsistem, dar nu le ascunde. Este important să înțelegem că clientul, în același timp, nu este privat de acces la nivel inferior la clasele subsistemului, dacă, desigur, are nevoie de el. Fațada simplifică anumite operațiuni cu subsistemul, dar nu impune clientului utilizarea acestuia.

Problema practica

Folosind modelul „Fațadă”, vom implementa o interfață unificată pentru un subsistem de autorizare a utilizatorului. Subsistemul de autorizare în sine (în acest exemplu) cu siguranță nu pretinde a fi un „sistem complex”, dar reflectă în mod clar principalele avantaje ale modelului.

Diagrama de clasă

Să ne uităm la diagramă. Cadrul subsistemului de autorizare, pentru claritate, este evidențiat într-un dreptunghi. Fațada Autorizatorului oferă clientului o interfață unificată pentru lucrul cu subsistemul. În acest caz, există o singură metodă - authorize(), dar ar putea fi mai multe. În acest caz, clientul poate folosi fațada pentru a lucra cu subsistemul sau poate folosi direct clasele care îl compun. Procesul de autorizare în sine este destul de simplu. Pe baza numelui de utilizator, intrarea corespunzătoare din baza de date este căutată prin interfața DB. Apoi, parola intrării găsite este comparată cu parola specificată de utilizator.

Implementare in C#

În codul de implementare Nu clasa PgSQLDB.
folosind System;
folosind System.Collections.Generic ;
folosind System.Linq;
folosind System.Text;
folosind System.Security;

namespace Fațadă
{
//Clasă de utilizator abstractă
clasa abstractă Utilizator
{
nume de utilizator șir protejat;
string protejat passwd;

șir public abstract getUserRole();

șir public getPasswdHash()
{
// Această linie nu poartă niciun sens semantic.
// Desigur, acest lucru ne oferă un hash de parolă nesigur
return passwd.GetHashCode().ToString();
}
}

// Specificați utilizatorul ca utilizator implicit
clasa DefaultUser: Utilizator
{
public DefaultUser (nume utilizator șir, passwd șir)
{
this .username = nume de utilizator;
this .passwd = passwd;
}


{
returnează „DEFAULT_USER” ;
}
}

// Specificați utilizatorul ca administrator
clasa Administrator: Utilizator
{
Administrator public (nume utilizator șir, passwd șir)
{
this .username = nume de utilizator;
this .passwd = passwd;
}

șir de suprascriere public getUserRole()
{
returnează „ADMINISTRATOR” ;
}

// Interfață de acces la baza de date
interfață DB
{
Căutare utilizator (șir nume de utilizator);
}

// Implementarea interfeței bazei de date pentru SQLite
clasa SQLiteDB:DB
{
public SQLiteDB(nume fișier șir)
{
// Inițializați driverul bazei de date
}

Căutare publică de utilizatori (șir nume de utilizator)
{
// Stub
aruncă o nouă excepție NotImplementedException();
}
}

// Autorizarea utilizatorului
public void autorizare (șir nume de utilizator, șir passwd)
{
DB db = new SQLiteDB("db.sqlite");
Utilizator utilizator = db.search(nume utilizator);
if (user.getPasswdHash() == passwd)
{
// totul este bine, utilizatorul este recunoscut
}
altfel
{
// ceva a mers prost
throw new SecurityException ("Parolă sau nume de utilizator greșit!");
}
}
}

Programul clasei
{
static void Main(string args)
{
// Utilizator fictiv
string username = "Vasya" ;
string passwd = "qwerty" .GetHashCode().ToString();

Authorizer auth = new Authorizer();
încerca
{
auth.authorizate(nume utilizator, passwd);
}
captură (SecurityException ex)
{
// Utilizatorul nu este autentificat
}
}
}
}


* Acest cod sursă a fost evidențiat cu Sursa de evidențiere a codului.

PS: Sunt singurul al cărui habraeditor nu funcționează?

Scopul modelului de fațadă

  • Modelul Fațadă oferă o interfață unificată în loc de un set de interfețe de subsistem. Fațada definește o interfață de nivel superior care face subsistemul mai ușor de utilizat.
  • Modelul Fațadă cuprinde un subsistem complex cu o interfață mai simplă.

Problema de rezolvat

Clienții doresc o interfață simplificată pentru funcționalitatea generală a unui subsistem complex.

Discuție despre modelul de fațadă

Modelul Fațadă încapsulează un subsistem complex într-un singur obiect de interfață. Acest lucru reduce timpul necesar pentru a învăța subsistemul și, de asemenea, ajută la reducerea gradului de cuplare dintre subsistem și un număr potențial mare de clienți. Pe de altă parte, dacă fațada este singurul punct de acces la subsistem, atunci va limita capabilitățile de care ar putea avea nevoie utilizatorii avansați.

Obiectul Fațadă care implementează funcțiile de mediere ar trebui să rămână destul de simplu și să nu fie un „oracol atotștiutor”.

Structura modelului fațadei

Clienții comunică cu subsistemul prin Facade. Când o solicitare este primită de la un client, obiectul Facade o redirecționează către componenta de subsistem dorită. Pentru clienți, componentele subsistemului rămân „un mister, învăluit în întuneric”.

Subsistemele SubsystemOne și SubsystemTree nu interacționează direct cu componentele interne ale subsistemului SubsystemTwo. Ei folosesc o „fațadă” SubsystemTwoWrapper (adică o abstractizare de nivel superior).

Modelul Fațadă definește o interfață unificată la nivel înalt pentru subsistem, făcându-l mai ușor de utilizat. Cumpărătorii se confruntă cu o fațadă atunci când comandă prin telefon produse de catalog. Cumpărătorul sună serviciul pentru clienți și listează articolele pe care dorește să le cumpere. Reprezentantul serviciului acționează ca o „față”, oferind o interfață pentru departamentul de onorare, departamentul de vânzări și serviciul de livrare.

  • Definiți o interfață simplă, unificată pentru subsistem.
  • Proiectați o clasă „wrapper” care încapsulează subsistemul.
  • Întreaga complexitate a subsistemului și interacțiunea componentelor acestuia sunt ascunse clienților. „Fațada”/„învelișul” transmite cererile utilizatorului către metodele de subsistem corespunzătoare.
  • Clientul folosește doar „fațada”.
  • Luați în considerare fezabilitatea creării de „fațade” suplimentare.

Caracteristicile modelului de fațadă

  • Fațade definește o nouă interfață, în timp ce Adapter folosește una existentă. Rețineți, Adapter face ca două interfețe existente să funcționeze împreună fără a crea altele noi.
  • În timp ce Flyweight arată cum să faci multe obiecte mici, Facade arată cum să faci un singur obiect care reprezintă un întreg subsistem.
  • Mediator este similar cu Facade prin faptul că face abstractie de funcționalitatea claselor existente. Cu toate acestea, Mediator centralizează funcționalitatea între obiectele de la egal la egal, care nu este inerentă niciunuia dintre ele. Colegii fac schimb de informații între ei prin Mediator. Pe de altă parte, Facade definește o interfață simplă la subsistem, nu adaugă funcționalități noi și nu este cunoscută de clasele subsistemului.
  • Abstract Factory poate fi folosit ca alternativă la Facade pentru a ascunde clasele specifice platformei.
  • Obiectele „Fațadă” sunt adesea Singleton, deoarece este necesar un singur obiect Fațadă.
  • Adaptor și Facade sunt ambele ambalaje, dar sunt tipuri diferite de ambalaje. Scopul Facade este de a crea o interfață mai simplă, scopul Adaptor este de a adapta o interfață existentă. Fațada înfășoară de obicei mai multe obiecte, Adaptor înfășoară un singur obiect.

Implementarea modelului de fațadă

Descompunerea sistemului în componente reduce complexitatea acestuia. Puteți slăbi conexiunile dintre componentele sistemului utilizând modelul Fațadă. Obiectul de fațadă oferă o interfață unică, simplificată, cu componentele sistemului.

Exemplul de mai jos modelează un sistem de servicii de rețea. FacilitiesFacade ascunde structura internă a sistemului. Utilizatorul, după ce a făcut o dată o solicitare de service, apoi se întreabă despre progresul lucrării de 1-2 ori pe săptămână timp de 5 luni până când solicitarea sa este complet deservită.

#include clasa MisDepartment ( public: void submitNetworkRequest() ( _state = 0; ) bool checkOnStatus() ( _state++; if (_state == Complete) return 1; return 0; ) private: enum States (Received, DenyAllKnowledge, ReferClientToFacilities, Electrician NoFacilities, ElectricianS Facilities) , ElectricianDidItWrong, DispatchTehnician, SignedOff, DoesNotWork, FixElectriciansWiring, Complete ); clasă ElectricianUnion ( public: void submitNetworkRequest() ( _state = 0; ) bool checkOnStatus() ( _state++; if (_state == Complete) return 1; return 0; ) private: enum States (Received, RejectTheForm, SizeTheJob, SmokeAndJokeBreak, Wait , DoTheWrongJob, BlameTheEngineer, WaitToPunchOut, DoHalfAJob, ComplainToEngineer, GetClarification, CompleteTheJob, TurnInThePaperwork, Complete ); clasa FacilitiesDepartment ( public: void submitNetworkRequest() ( _state = 0; ) bool checkOnStatus() ( _state++; if (_state == Complete) return 1; return 0; ) privat: enumerare State (Received, AssignToEngineer, EngineerResearches, RequestIs EngineerNotLeavessible, , AssignToNewEngineer, NewEngineerResearches, ReassignEngineer, EngineerReturns, EngineerResearchesAgain, EngineerFillsOutPaperWork, Complete ); clasa FacilitiesFacade ( public: FacilitiesFacade() ( _count = 0; ) void submitNetworkRequest() ( _state = 0; ) bool checkOnStatus() ( _count++; /* Solicitare de serviciu primită */ if (_state == Received) ( _state++; / * Redirecționează solicitarea către inginer */ _engineer.submitNetworkRequest();<< "submitted to Facilities - " << _count << " phone calls so far" << endl; } else if (_state == SubmitToEngineer) { /* Если инженер свою работу выполнил, перенаправим запрос электрику */ if (_engineer.checkOnStatus()) { _state++; _electrician.submitNetworkRequest(); cout << "submitted to Electrician - " << _count << " phone calls so far" << endl; } } else if (_state == SubmitToElectrician) { /* Если электрик свою работу выполнил, перенаправим запрос технику */ if (_electrician.checkOnStatus()) { _state++; _technician.submitNetworkRequest(); cout << "submitted to MIS - " << _count << " phone calls so far" << endl; } } else if (_state == SubmitToTechnician) { /* Если техник свою работу выполнил, то запрос обслужен до конца */ if (_technician.checkOnStatus()) return 1; } /* Запрос еще не обслужен до конца */ return 0; } int getNumberOfCalls() { return _count; } private: enum States { Received, SubmitToEngineer, SubmitToElectrician, SubmitToTechnician }; int _state; int _count; FacilitiesDepartment _engineer; ElectricianUnion _electrician; MisDepartment _technician; }; int main() { FacilitiesFacade facilities; facilities.submitNetworkRequest(); /* Звоним, пока работа не выполнена полностью */ while (!facilities.checkOnStatus()) ; cout << "job completed after only " << facilities.getNumberOfCalls() << " phone calls" << endl; }

Ieșire program:

transmis la Facilități - 1 apeluri telefonice transmise până acum la electrician - 12 apeluri telefonice până acum transmise la MIS - 25 apeluri telefonice până acum lucrare finalizată după doar 35 de apeluri telefonice

Fațada este un model de design comportamental. Acest model vă permite să ascundeți complexitatea sistemului prin reducerea tuturor apelurilor posibile la un singur obiect care le delegă obiectelor de sistem corespunzătoare.

Cea mai simplă schemă a modului în care funcționează modelul:

Să ne imaginăm că scriem software pentru un cuptor cu microunde. Pentru simplitate, să ne imaginăm că are doar următoarele funcții: întoarceți la stânga și la dreapta, setați puterea necesară, notificați despre începutul și sfârșitul lucrului.

Pentru a pregăti un fel de mâncare delicios, a încălzi ceva sau a-l dezgheța, trebuie să efectuați un anumit număr de acțiuni diferite într-o anumită secvență. De exemplu, la dezghețare, este necesar, începând de la puteri mari, să resetați puterea de mai multe ori, în timp ce se rotește platforma cu produsul.

Dacă utilizatorul ar trebui să urmeze el însuși fiecare pas al procesului, ar consuma foarte mult timp și ar fi ineficient. La urma urmei, toată lumea știe că pe un cuptor cu microunde modern este suficient să selectați programul dorit și să apăsați start, după care va face tot ce este necesar, iar la finalizare va anunța utilizatorul.

Modelul de design al fațadei se ocupă doar de astfel de cazuri. Vă permite să ascundeți toată complexitatea procesului în spatele unei interfețe simple.

Să creăm clase pentru funcționarea unității cu microunde (rotație), putere și notificare.

În clasa de mașini, vor exista doar 2 acțiuni: virați la dreapta și virați la stânga.

Class Drive ( public void TurlLeft() ( Console.WriteLine("Rotire la stânga"); ) public void TurlRight() ( Console.WriteLine("Rotire la dreapta"); ) )

În clasa care specifică puterea, a fost adăugată o proprietate pentru a obține și a seta puterea necesară de lucru.

Clasa Putere ( private int _power; public int MicrowavePower ( get ( return _power; ) set ( _power = valoare; Console.WriteLine ("Putere set (0)w ", _power); ) ) )

Au fost adăugate metode la clasa de notificare pentru a notifica despre începutul și sfârșitul lucrului.

Notificare de clasă ( public void StopNotification() ( Console.WriteLine("Vârf-vârf-vârf - operațiunea este finalizată"); ) public void StartNotification() ( Console.WriteLine("Vârf - procesul de gătit a început"); ) )

Tot ce rămâne este să implementezi clasa cuptorului cu microunde în sine. În acest exemplu, va fi și fațada. În clasă implementăm metode de dezghețare și încălzire a alimentelor.

Clasa Cuptor cu microunde ( drive privat _drive; private Power _power; private Notification _notification; public Microwave(Drive drive, Power power, Notification notification) ( _drive = drive; _power = power; _notification = notification; ) public void Defrost() ( _notification.StartNotification (); _power.MicrowavePower = _drive.TurlRight(); _drive = 350; _drive.TurlRight(); _drive.TurlLeft();

) )

Atât, exemplul este gata, nu mai rămâne decât să-l testăm.

Var drive = nou Drive(); var putere = noua putere(); var notificare = new Notification(); var microwave = new Microwave.Microwave(drive, power, notification); Console.WriteLine("Deblocați"); cuptor cu microunde.Decongelare(); Console.WriteLine(); Console.WriteLine("Să-l încălzim"); cuptor cu microunde.Incalzire();


Rezultatul va fi următorul:

Înainte de a citi, vă rugăm să revizuiți următoarele convenții și concepte. Acest articol este actualizat cu o oarecare frecvență, așa că dacă l-ați citit înainte, nu este un fapt că datele nu s-au schimbat. Faţadă aparțin clasei structural

modele. Reprezintă o interfață unificată în loc de un set de interfețe ale unui anumit subsistem. Modelul de fațadă definește o interfață de nivel superior care face subsistemele mai ușor de utilizat.

Împărțirea unui sistem complex în subsisteme vă permite să simplificați procesul de proiectare și, de asemenea, vă ajută să minimizați dependențele unui subsistem de altul. Cu toate acestea, acest lucru duce la faptul că utilizarea împreună a unor astfel de subsisteme devine destul de dificilă. O modalitate de a rezolva această problemă este introducerea unui model de fațadă.

Dreptunghiul gri conține subsistemele noastre, care au unele dependențe între ele (s-ar putea să nu). Primele trei blocuri indică cele trei secțiuni ale codului client în care interacționează cu acest subsistem. Sarcina noastră este să realizăm o interfață simplă, unificată prin care ar fi suficient să interacționăm cu subsistemele în cadrul sarcinii, aceste. nu trebuie să facem o interfață universală pentru toate ocaziile, deoarece în majoritatea cazurilor acest lucru este inutil și duce la interacțiuni mai complexe și la creșterea timpului de dezvoltare.

Mai jos este o schiță a unei implementări:

/** * SystemA */ class Bank (funcție publică OpenTransaction() () public function CloseTransaction() () public function transferMoney($amount) () ) /** * SystemB */ class Client (funcție publică OpenTransaction() () ( ) public function CloseTransaction() () public function transferMoney($amount) () ) /** * SystemC */ class Jurnal ( public function logTransaction() () ) class Façade ( public function transfer($amount) ( $Bank = new Bank (); $Log = new Log(); ; $Client->CloseTransaction(); $Log->logTransaction("Transaction close" ) ) // Cod client $Transfer = new Façade(); $Transfer->transfer(1000);

Descrierea fațadei la distanță

Oferă o interfață de unificare comună pentru un set de metode obiect pentru a îmbunătăți eficiența rețelei.

Modelul Remote Facade din modelul orientat pe obiecte îmbunătățește lucrul cu obiecte mici care au metode mici. Tehnicile mici oferă oportunități mari de a controla și schimba comportamentul și de a îmbunătăți înțelegerea de către client a aplicației. O consecință a acestui comportament fin este că există de obicei multă interacțiune între obiecte, cu multe apeluri de metodă.

Într-un spațiu de adresă, interacțiunile „finite” funcționează bine, dar totul se schimbă atunci când interacțiunea are loc între procese. Apelurile de la distanță sunt mai scumpe pentru că trebuie făcut multe: uneori datele trebuie organizate, verificate pentru securitate, pachetele trebuie direcționate pe comutatoare. Dacă două procese operează la capturi diferite ale lumii, chiar și viteza luminii poate juca un rol. Adevărul dur este că orice comunicare între procese este mult mai risipitoare decât apelurile intraproces. Chiar dacă ambele procese rulează pe aceeași mașină. Acest impact asupra performanței nu poate fi trecut cu vederea, chiar și de către pasionații leneși de optimizare.

Ca rezultat, orice obiect care este implicat în telecomunicarea are nevoie de o interfață mai generală care să minimizeze numărul de solicitări necesare pentru a face ceva. Acest lucru afectează nu numai metodele, ci și obiectele. În loc să solicitați o factură și toate elementele acesteia separat, trebuie să citiți și să actualizați toate elementele facturii într-o singură solicitare. Acest lucru afectează întreaga structură a obiectului. Trebuie să uităm de scopul bun al obiectelor mici și al metodelor mici. Programarea devine din ce în ce mai dificilă, productivitatea scade și scade.

Modelul Remote Facade reprezintă o „Fațadă” generală (conform GoF) deasupra unei structuri de obiecte mai „granulate fin”. Niciunul dintre aceste obiecte nu are o interfață la distanță, iar Fațada la distanță nu include nicio logică de afaceri. Tot ceea ce face Remote Facade este să traducă cererile generale într-un set de cereri mici pentru obiecte subordonate.