Bună! Acum continuăm să aprofundăm într-un subiect util amplu și foarte important: modelele de design. Astăzi să vorbim despre modelul podului. Ca și alte modele, modelul bridge servește la rezolvarea problemelor tipice pe care le întâmpină un dezvoltator atunci când proiectează arhitectura software. Astăzi, să studiem caracteristicile acestui model și să aflăm cum să-l folosim.

Care este modelul podului?

Modelul podului este un model de proiectare structurală. Cu alte cuvinte, sarcina sa principală este de a crea o structură cu drepturi depline din clase și obiecte. O punte face acest lucru împărțind una sau mai multe clase în ierarhii separate: abstractizare și implementare . O modificare a funcționalității într-o ierarhie nu implică o schimbare în cealaltă. Toate acestea sunt bune și bune, dar această definiție este foarte largă și nu răspunde la cea mai importantă întrebare: „Care este modelul podului?” Cred că vă va fi mai ușor să înțelegeți aplicarea sa practică. Deci, imediat, să creăm un scenariu clasic pentru modelul podului. Avem o Shapeclasă abstractă, care reprezintă o figură geometrică generică:
  • Formă.java

    
    public abstract class Shape {
       public abstract void draw();
    }
    

    Când decidem să adăugăm forme precum triunghiuri și dreptunghiuri, le vom face să moștenească Shapeclasa:

  • Rectangle.java:

    
    public class Rectangle extends Shape {
       @Override
       public void draw() {
           System.out.println("Drawing rectangle");
       }
    }
    
  • Triangle.java:

    
    public class Triangle extends Shape {
       @Override
       public void draw() {
           System.out.println("Drawing triangle");
       }
    }
    
Totul pare simplu pana in momentul in care introducem conceptul de culoare. Adică, fiecare formă va avea propria sa culoare, iar funcționalitatea metodei draw()va depinde de această culoare. Pentru a avea implementări diferite ale draw()metodei, atunci trebuie să creăm o clasă pentru fiecare combinație formă-culoare. Dacă avem trei culori, atunci avem nevoie de șase clase: TriangleBlack, TriangleGreen, TriangleRed, și . Șase clase nu este o problemă atât de mare. Dar! Dacă trebuie să adăugăm o nouă formă sau culoare, atunci numărul de clase crește exponențial. Cum să ieși din această situație? Stocarea culorii într-un câmp și enumerarea tuturor opțiunilor folosind instrucțiuni condiționale nu este cea mai bună soluție. O soluție bună este să mutați culoarea într-o interfață separatăRectangleBlackRectangleGreenRectangleRed. Nu mai devreme de spus, de făcut: să creăm o Colorinterfață cu trei implementări: și : BlackColorGreenColorRedColor
  • Color.java:

    
    public interface Color {
       void fillColor();
    }
    
  • BlackColor.java:

    
    public class BlackColor implements Color {
       @Override
       public void fillColor() {
           System.out.println("Filling in black color");
       }
    }
    
  • GreenColor.java

    
    public class GreenColor implements Color {
       @Override
       public void fillColor() {
           System.out.println("Filling in green color");
       }
    }
    
  • RedColor.java

    
    public class RedColor implements Color {
       @Override
       public void fillColor() {
           System.out.println("Filling in red color");
       }
    }
    

    Acum adăugăm un Colorcâmp la Shapeclasă. Îi vom obține valoarea în constructor.

  • Shape.java:

    
    public abstract class Shape {
       protected Color color;
      
       public Shape(Color color) {
           this.color = color;
       }
    
       public abstract void draw();
    }
    

    Vom folosi colorvariabila în Shapeimplementări. Aceasta înseamnă că formele pot folosi acum funcționalitatea interfeței Color.

  • dreptunghi.java

    
    public class Rectangle extends Shape {
    
       public Rectangle(Color color) {
           super(color);
       }
    
       @Override
       public void draw() {
           System.out.println("Drawing rectangle");
           color.fillColor();
       }
    }
    
Ta-da! Acum putem crea diferite culori și forme la infinit, iar numărul de clase va crește doar liniar. Câmpul Color coloreste o punte care conectează două ierarhii de clasă separate.

Cum să construiești o punte: abstractizare și implementare

Să ne uităm la o diagramă de clasă care ilustrează modelul de punte: Prezentarea modelului de proiectare a podului - 2Aici puteți vedea două structuri independente care pot fi modificate fără a afecta funcționalitatea celuilalt. În cazul nostru:
  • Abstracția este Shapeclasa
  • RefinedAbstraction este clasele TriangleșiRectangle
  • Implementator este Colorinterfața
  • ConcreteImplementor este clasele BlackColorși .GreenColorRedColor
Clasa Shapeeste o abstractizare — un mecanism de gestionare a umplerii formelor cu diferite culori, care se deleagă la Colorinterfață (Implementor). Clasele Triangleși Rectanglesunt clase concrete care folosesc mecanismul pus la dispoziție de Shapeclasă. BlackColor, GreenColorși RedColorsunt implementări concrete în ierarhia de implementare.

Unde să folosiți modelul de punte

Un avantaj uriaș al utilizării acestui model este că puteți face modificări la clasele funcționale dintr-o ierarhie fără a rupe logica celeilalte. De asemenea, această abordare ajută la reducerea cuplării dintre clase. Principala cerință atunci când utilizați acest model este „urmați instrucțiunile” - nu ignorați niciunul dintre ele! În acest scop, să descoperim situațiile în care ar trebui să utilizați cu siguranță modelul de punte:
  1. Dacă trebuie să extindeți numărul de entități pe baza combinațiilor a două concepte (de exemplu, forme și culori).

  2. Dacă doriți să împărțiți o clasă mare care nu îndeplinește principiul responsabilității unice în clase mai mici care au funcționalitate îngustă.

  3. Dacă este necesar să faceți modificări în logica anumitor entități în timp ce programul rulează.

  4. Dacă este necesar să ascundeți o implementare de clienții clasei sau bibliotecii.

Când utilizați acest model, amintiți-vă întotdeauna că adaugă entități suplimentare la codul dvs. - s-ar putea să nu aibă sens să îl utilizați într-un proiect în care există doar o formă și una sau două culori posibile.

Avantaje și dezavantaje ale modelului

Ca și alte modele, un pod are atât avantaje, cât și dezavantaje. Avantajele modelului de punte:
  1. Îmbunătățește scalabilitatea codului - puteți adăuga funcționalitate fără teama de a sparge ceva într-o altă parte a programului.
  2. Reduce numărul de subclase atunci când numărul de entități s-ar baza altfel pe combinații a două concepte (de exemplu, forme și culori).
  3. Face posibilă lucrarea separată pe două ierarhii separate - Abstracție și Implementare. Doi dezvoltatori diferiți pot face modificări fără să intre în detaliile codului celuilalt.
  4. Reduce cuplarea dintre clase — singurul loc în care cele două clase sunt cuplate este puntea (adică câmpul Color color).
Dezavantajele modelului de punte:
  1. În funcție de situația specifică și de structura generală a unui proiect, acesta ar putea avea un impact negativ asupra performanței unui program (de exemplu, dacă trebuie să inițializați mai multe obiecte).
  2. Face codul mai puțin lizibil din cauza necesității de a comuta între cele două clase.

Diferență față de modelul de strategie

Modelul de punte este adesea confundat cu un alt model de design - strategia. Ambii folosesc compoziția (deși am folosit agregarea în exemplu cu figuri și culori, modelul Bridge poate folosi și compoziția), delegând munca altor obiecte. Dar există o diferență între ele și este uriașă. Modelul de strategie este un model comportamental: rezolvă probleme complet diferite. Strategia permite interschimbarea algoritmilor, în timp ce bridge-ul separă o abstractizare de implementări pentru a alege între diferite implementări. Cu alte cuvinte, spre deosebire de o strategie, o punte se aplică unor entități întregi sau structuri ierarhice. Modelul de punte poate fi o armă bună în arsenalul unui dezvoltator. Principalul lucru este să identificați situațiile în care merită să îl utilizați și să recunoașteți când este adecvat un alt model.