Wzór mostka

Wzorzec pomostowy to wzorzec projektowy używany w inżynierii oprogramowania , który ma na celu „oddzielenie abstrakcji od jej implementacji , tak aby oba mogły się różnić niezależnie” , wprowadzony przez Gang of Four . Most wykorzystuje enkapsulację , agregację i może wykorzystywać dziedziczenie do rozdzielania obowiązków na różne klasy .

Kiedy klasa często się zmienia, funkcje programowania obiektowego stają się bardzo przydatne, ponieważ zmiany w kodzie programu można łatwo wprowadzić przy minimalnej wcześniejszej wiedzy o programie. Wzorzec mostka jest przydatny, gdy zarówno klasa, jak i to, co robi, często się zmienia. Sama klasa może być traktowana jako abstrakcja , a to, co klasa może zrobić, to implementacja . Wzór mostu można również traktować jako dwie warstwy abstrakcji.

Gdy istnieje tylko jedna stała implementacja, ten wzorzec jest znany jako idiom Pimpl w świecie C++ .

Wzorzec mostka jest często mylony ze wzorcem adaptera i często jest implementowany przy użyciu wzorca adaptera obiektowego ; np. w poniższym kodzie Java.

Wariant: Implementację można jeszcze bardziej oddzielić, odkładając obecność implementacji do punktu, w którym abstrakcja jest wykorzystywana.

Przegląd

Wzorzec projektowy Bridge jest jednym z dwudziestu trzech dobrze znanych wzorców projektowych GoF , które opisują, jak rozwiązywać powtarzające się problemy projektowe w celu zaprojektowania elastycznego i wielokrotnego użytku zorientowanego obiektowo oprogramowania, czyli obiektów, które są łatwiejsze do wdrożenia, zmiany, testowania i ponowne użycie.

Jakie problemy może rozwiązać wzorzec projektowy Bridge?

  • Abstrakcja i jej implementacja powinny być definiowane i rozszerzane niezależnie od siebie.
  • Należy unikać powiązania w czasie kompilacji między abstrakcją a jej implementacją, aby można było wybrać implementację w czasie wykonywania.

Podczas korzystania z podklas, różne podklasy implementują klasę abstrakcyjną na różne sposoby. Ale implementacja jest powiązana z abstrakcją w czasie kompilacji i nie można jej zmienić w czasie wykonywania.

Jakie rozwiązanie opisuje wzorzec projektowy Bridge?

  • Oddziel abstrakcję ( Abstraction ) od jej implementacji ( Implementor ), umieszczając je w osobnych hierarchiach klas.
  • Zaimplementuj Abstrakcję w kategoriach (delegując do) obiektu Implementor .


Umożliwia to skonfigurowanie abstrakcji z obiektem Implementor w czasie wykonywania. Zobacz także diagram klas i sekwencji Unified Modeling Language poniżej.

Struktura

Diagram klas i sekwencji UML

Przykładowy diagram klas i sekwencji UML dla wzorca projektowego Bridge.


Na powyższym diagramie klas Unified Modeling Language abstrakcja ( Abstraction ) nie jest zaimplementowana jak zwykle w pojedynczej hierarchii dziedziczenia. Zamiast tego istnieje jedna hierarchia dla abstrakcji ( Abstraction ) i oddzielna hierarchia dla jej implementacji ( Implementor ), co czyni je niezależnymi od siebie. Interfejs abstrakcji ( operation() ) jest implementowany w kategoriach (poprzez delegowanie do) interfejsu Implementora ( imp.operationImp() ). Diagram sekwencji UML pokazuje interakcje w czasie wykonywania: Obiekt Abstract1 deleguje implementację do obiektu Implementor1 (poprzez wywołanie operationImp() na Implementor1 ), który wykonuje operację i powraca do Abstraction1 .

Diagram klas

Bridge UML class diagram.svg

Abstrakcja (klasa abstrakcyjna)
definiuje abstrakcyjny interfejs,
który utrzymuje referencję Implementora.
RefinedAbstraction (klasa normalna)
rozszerza interfejs zdefiniowany przez Abstraction
Implementor (interfejs)
definiuje interfejs dla klas implementacji
ConcreteImplementor (klasa normalna)
implementuje interfejs Implementor
Most w LePUS3 ( legenda )

Przykład

C#

Wzór mostu komponuje obiekty w strukturze drzewa. Oddziela abstrakcję od implementacji. Tutaj abstrakcja reprezentuje klienta, z którego zostaną wywołane obiekty. Poniżej podano przykład zaimplementowany w języku C#


  

     
     


    

      
    
        
    

      
    
        
    


    

      
    
        
    

      
    
        
    


  

     
     


    

      

      
    
          
    

      
    
        
    

      
    
        
    
 // Pomaga w zapewnieniu prawdziwie oddzielonej architektury  publicznego  interfejsu  IBridge  {  void  Function1  ();  pusta  Funkcja2  ();  }  public  class  Bridge1  :  IBridge  {  public  void  Function1  ()  {  Console  .  WriteLine  (  "Most1.Funkcja1"  );  }  public  void  Funkcja2  ()  {  Konsola  .  WriteLine  (  "Most1.Funkcja2"  );  }  }  public  class  Bridge2  :  IBridge  {  public  void  Function1  ()  {  Console  .  WriteLine  (  "Most2.Funkcja1"  );  }  public  void  Funkcja2  ()  {  Konsola  .  WriteLine  (  "Most2.Funkcja2"  );  }  }  interfejs  publiczny  IAbstractBridge  {  void  CallMethod1  ();  nieważna  metoda wywołania2  ();  }  klasa  publiczna  AbstractBridge  :  IAbstractBridge  {  publiczny  most  IBridge  ;  public  AbstractBridge  (  most  IBridge  )  {  to  .  most  =  most  ;  }  public  void  CallMethod1  ()  {  this  .  most  .  Funkcja1  ();  }  public  void  CallMethod2  ()  {  this  .  most  .  Funkcja2  ();  }  } 

Klasy Bridge to Implementacja, która używa tej samej architektury zorientowanej na interfejs do tworzenia obiektów. Z drugiej strony abstrakcja pobiera instancję klasy implementacji i uruchamia jej metodę. W ten sposób są one całkowicie oddzielone od siebie.

Kryształ

  
            


   
           
    
  


   
           
    
  


  
      

   
  

    
      


   
     
     
     

        
    
  

   
      
  

     
        
  


 
   
        
         
         

      
      
       
    
  


 Klasa  abstrakcyjna  DrawingAPI  abstract  def  draw_circle  (  x  :  Float64  ,  y  :  Float64  ,  radius  :  Float64  )  end  class  DrawingAPI1  <  DrawingAPI  def  draw_circle  (  x  :  Float  ,  y  :  Float  ,  radius  :  Float  )  "API1.circle at  #{  x  }  :  # {  y  }  - radius:  #{  radius  }  "  end  end  class  DrawingAPI2  <  DrawingAPI  def  draw_circle  (  x  :  Float64  ,  y  :  Float64  ,  radius  :  Float64  )  "API2.circle at  #{  x  }  :  #{  y  }  - promień:  # {  radius  }  "  end  end  abstract  class  Shape  protected  getter  drawing_api  :  DrawingAPI  def  initialize  (  @drawing_api  )  end  abstract  def  draw  abstract  def  resize_by_percentage  (  percent  :  Float64  )  end  class  CircleShape  <  Shape  getter  x  :  Float64  getter  y  :  Float64  getter  radius  :  Float64  def  inicjalizacja  (  @x  ,  @y  ,  @radius  ,  drawing_api  :  DrawingAPI  )  super  (  drawing_api  )  koniec  def  draw  @drawing_api  .  draw_circle  (  @x  ,  @y  ,  @radius  )  end  def  resize_by_percentage  (  procent  :  Float64  )  @radius  *=  (  1  +  percent  /  100  )  end  end  class  BridgePattern  def  self  .  kształty  testowe  =  [  ]  kształtów  kształtów  <<  CircleShape  .  nowe  (  1.0  ,  2.0  ,  3.0  ,  DrawingAPI1  .  nowe  )  kształty  <<  CircleShape  .  nowe  (  5.0  ,  7.0  ,  11.0  ,  DrawingAPI2  .  nowe  )  kształty  .  każdy  robi  |  kształt  |  kształt  .  resize_by_percentage  (  2.5  )  nadaje  kształt  .  rysuj  koniec  koniec  koniec  BridgePattern  .  test 

Wyjście

API1.circle na 1.0:2.0 - promień: 3.075 API2.circle na 5.0:7.0 - promień: 11.275

C++

 
 
 


  
  
       
              0


     
  
             
              
           
    


     
  
             
              
           
    


  
  
         
       

         0
          0

  
      


    
      
            
           

        
           
    

         
           
    
  
  
       


     
    
    
    
       
       
   

      
    
        
  

   0
 #include  <iostream>  #include  <string>  #include  <wektor>  class  DrawingAPI  {  public  :  virtual  ~  DrawingAPI  ()  =  default  ;  virtual  std  ::  string  DrawCircle  (  float  x  ,  float  y  ,  float  promień  )  const  =  ;  };  class  DrawingAPI01  :  public  DrawingAPI  {  public  :  std  ::  string  DrawCircle  (  float  x  ,  float  y  ,  float  radius  )  const  override  {  return  "API01.circle at"  +  std  ::  to_string  (  x  )  +  ":"  +  std  ::  to_string  (  y  )  +  " - promień: "  +  std  ::  to_string  (  promień  );  }  };  class  DrawingAPI02  :  public  DrawingAPI  {  public  :  std  ::  string  DrawCircle  (  float  x  ,  float  y  ,  float  radius  )  const  override  {  return  "API02.circle at"  +  std  ::  to_string  (  x  )  +  ":"  +  std  ::  to_string  (  y  )  +  " - promień: "  +  std  ::  to_string  (  promień  );  }  };  class  Shape  {  public  :  Shape  (  const  DrawingAPI  &  drawing_api  )  :  drawing_api_  (  drawing_api  )  {}  virtual  ~  Shape  ()  =  default  ;  virtual  std  ::  string  Draw  ()  const  =  ;  virtual  float  ResizeByPercentage  (  const  float  percent  )  =  ;  chroniony  :  const  DrawingAPI  &  drawing_api_  ;  };  class  CircleShape  :  public  Shape  {  public  :  CircleShape  (  float  x  ,  float  y  ,  float  promień  ,  const  DrawingAPI  &  drawing_api  )  :  Shape  (  drawing_api  ),  x_  (  x  ),  y_  (  y  ),  radius_  (  radius  )  {}  std  ::  string  Draw  ()  const  override  {  return  drawing_api_  .  RysujOkrąg  (  x_  ,  y_  ,  promień_  );  }  float  ResizeByPercentage  (  const  float  percent  )  override  {  return  radius_  *=  (  1.0f  +  procent  /  100.0f  );  }  prywatne  :  float  x_  ,  y_  ,  promień_  ;  };  int  main  (  int  argc  ,  char  **  argv  )  {  const  DrawingAPI01  api1  {};  const  DrawingAPI02  api2  {};  std  ::  vector  <  kształt okręgu  >  kształty  {  kształt okręgu  {  1.0f  ,  2.0f  ,  3.0f  ,  api1  },  kształt okręgu  {  5.0f  ,  7.0f  ,  11.0f  ,  api2  }  };  for  (  auto  &  kształt  :  kształty  )  {  kształt  .  ResizeByPercentage  (  2.5  );  std  ::  cout  <<  kształt  .  Rysuj  ()  <<  std  ::  endl  ;  }  powrót  ;  } 

Wyjście:

API01.circle na 1.000000:2.000000 - promień: 3.075000 API02.circle na 5.000000:7.000000 - promień: 11.275000

Jawa

Poniższy program Java definiuje konto bankowe, które oddziela operacje na koncie od rejestrowania tych operacji.



  
      
    
       
             
    
       
             
    


   
        
    
        
          
    
    
    
          
            
    


    
      
    
       
          
    
    
       
           
    
    
        
             
          
              
        
           
    


   
         
            
        
        
          
            
            
        
        
        
        
    
 // Logger ma dwie implementacje: info i ostrzeżenie  @FunctionalInterface  interface  Logger  {  void  log  (  String  message  );  static  Informacje  o rejestratorze  ()  {  wiadomość  zwrotna  ->  System  .  na  zewnątrz  println  (  "informacje:"  +  wiadomość  );  }  static  Ostrzeżenie  rejestratora  ()  {  komunikat  zwrotny  ->  System  .  na  zewnątrz  println  (  "ostrzeżenie: "  +  wiadomość  );  }  }  Klasa  abstrakcyjna  AbstractAccount  {  private  Logger  logger  =  Logger  .  informacje  ();  public  void  setLogger  (  Logger  rejestratora  )  {  to  .  rejestrator  =  rejestrator  ;  }  // część rejestrowania jest przekazywana do implementacji Loggera  chronionej przed  operacją  void  (  Komunikat  łańcuchowy  ,  wynik  boolowski  )  {  logger  .  dziennik  (  wiadomość  +  „wynik”  +  wynik  );  }  }  class  SimpleAccount  extends  AbstractAccount  {  private  int  balance  ;  public  SimpleAccount  (  int  balance  )  {  to  .  równowaga  =  równowaga  ;  }  public  boolean  isBalanceLow  ()  {  saldo  zwrotu  <  50  ;  }  public  void  wycofaj  (  int  kwota  )  {  boolean  shouldPerform  =  saldo  >=  kwota  ;  if  (  należy wykonać  )  {  saldo  -=  kwota  ;  }  działać  (  "wypłata"  +  kwota  ,  shouldPerform  );  }  }  public  class  BridgeDemo  {  public  static  void  main  (  String  []  args  )  {  SimpleAccount  account  =  new  SimpleAccount  (  100  );  konto  .  wycofać  (  75  );  if  (  account  .  isBalanceLow  ())  {  // możesz także zmienić implementację Loggera w runtime  account  .  setLogger  (  Rejestrator  .  ostrzeżenie  ());  }  konto  .  wycofać  (  10  );  konto  .  wycofać  (  100  );  }  } 

Wyprowadzi:

info: wycofaj 75 wynik prawda ostrzeżenie: wycofaj 10 wynik prawda ostrzeżenie: wycofaj 100 wynik fałsz

PHP

 

       


   

        
    
         
    


   

        
    
         
    


  

     

       
       

       
    
          
    


   

     
     
     

          
    
        
          
          
          
    

      
    
          
    

      
    
          
    


 

       
    
          
                  
                 
        

            
            
            
        
    


 interfejs  DrawingAPI  {  funkcja  drawCircle  (  $x  ,  $y  ,  $radius  );  }  class  DrawingAPI1  implementuje  DrawingAPI  {  public  function  drawCircle  (  $x  ,  $y  ,  $radius  )  {  echo  "API1.circle at  $x  :  $y  promień  $radius  .  \n  "  ;  }  }  class  DrawingAPI2  implementuje  DrawingAPI  {  public  function  drawCircle  (  $x  ,  $y  ,  $radius  )  {  echo  "API2.circle at  $x  :  $y  promień  $radius  .  \n  "  ;  }  }  Klasa  abstrakcyjna  Kształt  {  chroniony  $drawingAPI  ;  rysowanie  publicznej  funkcji  abstrakcyjnej  ();  publiczna  funkcja  abstrakcyjna  resizeByPercentage  (  $pct  );  funkcja  chroniona  __construct  (  DigitalAPI  $drawingAPI  )  {  $this  ->  drawingAPI  =  $drawingAPI  ;  }  }  klasa  CircleShape  rozszerza  Shape  {  private  $x  ;  prywatne  $y  ;  prywatny  promień $  ;  funkcja  publiczna  __construct  (  $x  ,  $y  ,  $radius  ,  DrawingAPI  $drawingAPI  )  {  rodzic  ::  __construct  (  $drawingAPI  );  $to  ->  x  =  $x  ;  $to  ->  y  =  $y  ;  $to  ->  promień  =  $promień  ;  }  rysowanie  funkcji  publicznej  ()  {  $to  ->  rysowanie API  ->  rysowanieOkręgu  (  $ to  ->  x  ,  $ to  ->  y  ,  $ to  ->  promień  );  }  funkcja  publiczna  resizeByPercentage  (  $pct  )  {  $this  ->  promień  *=  $pct  ;  }  }  class  Tester  {  public  static  function  main  ()  {  $shapes  =  array  (  new  CircleShape  (  1  ,  3  ,  7  ,  new  DrawingAPI1  ()),  new  CircleShape  (  5  ,  7  ,  11  ,  new  DrawingAPI2  ()),  );  foreach  (  $kształty  jako  $ kształt  )  {  $ kształt  ->  resizeByPercentage  (  2.5  );  $kształt  ->  rysuj  ();  }  }  }  Tester  ::  main  (); 

Wyjście:

API1.circle w promieniu 1:3 17,5 API2.circle w promieniu 5:7 27,5

Scala

  
        


    
            


    
            


    
   
    


         
       

       

         


  
     
     
	     
	     
        
        
        			
      	
  
 Cecha  DrawingAPI  {  def  drawCircle  (  x  :  Double  ,  y  :  Double  ,  promień  :  Double  )  }  class  DrawingAPI1  extends  DrawingAPI  {  def  drawCircle  (  x  :  Double  ,  y  :  Double  ,  radius  :  Double  )  =  println  (  s"API #1  $  x  $  y  $  promień  "  )  }  class  DrawingAPI2  extends  DrawingAPI  {  def  drawCircle  (  x  :  Double  ,  y  :  Double  ,  radius  :  Double  )  =  println  (  s"API #2  $  x  $  y  $  promień  "  )  }  abstract  class  Shape  (  drawingAPI  :  DrawingAPI  )  {  def  draw  ( )  def  resizePercentage  (  pct  :  Double  )  }  class  CircleShape  (  x  :  Double  ,  y  :  Double  ,  var  radius  :  Double  ,  drawingAPI  :  DrawingAPI  )  extends  Shape  (  drawingAPI  :  DrawingAPI  )  {  def  draw  ( )  =  drawingAPI  .  drawCircle  (  x  ,  y  ,  promień  )  def  resizePercentage  (  pct  :  Double  )  {  promień  *=  pct  }  }  object  BridgePattern  {  def  main  (  args  :  Array  [  String  ])  {  Seq  (  new  CircleShape  (  1  ,  3  ,  5  ,  new  DrawingAPI1  ) ,  nowy  CircleShape  (  4  ,  5  ,  6  ,  nowy  DrawingAPI2  )  )  foreach  {  x  =>  x  .  zmień rozmiarProcent  (  3  )  x  .  rysuj  ()  }  }  } 

Pyton




    


  


 
      

    
        
         


 
        
         


 
        
         


 
        
         


 
      

      
      
          

    
     
         

    
      
         


 
         
          
          
          
         


     
           

      
              


 
    
     
          
               
               
               
        

           
            
            


 """  Przykład wzorca mostka.  """  z  abc  import  ABCMeta  ,  abstractmethod  NOT_IMPLEMENTED  =  "Powinieneś to zaimplementować."  class  DrawingAPI  :  __metaclass__  =  ABCMeta  @abstractmethod  def  draw_circle  (  self  ,  x  ,  y  ,  radius  ):  podnieś  NotImplementedError  (  NOT_IMPLEMENTED  )  class  DrawingAPI1  (  DrawingAPI  ):  def  draw_circle  (  self  ,  x  ,  y  ,  radius  ):  return  f  "API1.circle at  {  x  }  :  {  y  }  - promień:  {  promień  }  "  class  DrawingAPI2  (  DrawingAPI  ):  def  draw_circle  (  self  ,  x  ,  y  ,  radius  ):  return  f  "API2.circle at  {  x  }  :  {  y  }  - promień:  {  promień  }  "  class  DrawingAPI3  (  DrawingAPI  ):  def  draw_circle  (  self  ,  x  ,  y  ,  radius  ):  return  f  "API3.circle at  {  x  }  :  {  y  }  - radius:  {  promień  }  "  class  Shape  :  __metaclass__  =  ABCMeta  drawing_api  =  Brak  def  __init__  (  self  ,  drawing_api  ):  self  .  drawing_api  =  drawing_api  @abstractmethod  def  draw  (  self  ):  podnieś  NotImplementedError  (  NOT_IMPLEMENTED  )  @abstractmethod  def  resize_by_percentage  (  self  ,  percent  ):  podnieś  NotImplementedError  (  NOT_IMPLEMENTED  )  class  CircleShape  (  Shape  ):  def  __init__  (  self  ,  x  ,  y  ,  radius  ,  drawing_api  ) :  ja  .  x  =  x  ja  .  y  =  y  siebie  .  promień  =  promień  super  (  kształt okręgu  ,  własny  )  .  __init__  (  drawing_api  )  def  draw  (  self  ):  zwraca  self  .  rysunek_api  .  draw_circle  (  self.x  ,  self.y  ,  self.radius  )  def  resize_by_percentage  (  self  ,  percent  )  :  self  .  _  _  _  _  _  promień  *=  1  +  procent  /  100  klasa  BridgePattern  :  @staticmethod  def  test  ():  Shapes  =  [  CircleShape  (  1.0  ,  2.0  ,  3.0  ,  DrawingAPI1  ()),  CircleShape  (  5.0  ,  7.0  ,  11.0  ,  DrawingAPI2  ()),  CircleShape  (  5.0  ,  4.0  ,  12.0  ,  DrawingAPI3  ()),  ]  dla  kształtu  w  kształtach  :  kształt  .  resize_by_percentage  (  2.5  )  print  (  kształt  .  rysuj  ())  BridgePattern  .  test  () 

Zobacz też

Linki zewnętrzne