نمط الجسر

نمط الجسر هو نمط تصميم يستخدم في هندسة البرمجيات ويهدف إلى "فصل التجريد عن تنفيذه بحيث يمكن للاثنين أن يختلفا بشكل مستقل" ، وقد قدمه Gang of Four . [1] يستخدم الجسر التغليف والتجميع ويمكنه استخدام الميراث لفصل المسؤوليات إلى فئات مختلفة .

عندما تتنوع الفئة بشكل متكرر، تصبح ميزات البرمجة الموجهة للكائنات مفيدة للغاية لأنه يمكن إجراء تغييرات على كود البرنامج بسهولة مع الحد الأدنى من المعرفة المسبقة بالبرنامج. يكون نمط الجسر مفيدًا عندما تتنوع الفئة وما تفعله بشكل متكرر. يمكن اعتبار الفئة نفسها بمثابة التجريد وما يمكن للفئة فعله باعتباره التنفيذ . يمكن أيضًا اعتبار نمط الجسر بمثابة طبقتين من التجريد.

عندما يكون هناك تنفيذ ثابت واحد فقط، يُعرف هذا النمط باسم مصطلح Pimpl في عالم C++ .

غالبًا ما يتم الخلط بين نمط الجسر ونمط المحول ، وغالبًا ما يتم تنفيذه باستخدام نمط محول الكائن ؛ على سبيل المثال، في كود Java أدناه.

متغير: يمكن فصل التنفيذ بشكل أكبر عن طريق تأجيل وجود التنفيذ إلى النقطة التي يتم فيها استخدام التجريد.

ملخص

نمط تصميم الجسر هو أحد أنماط تصميم GoF الثلاثة والعشرين المعروفة التي تصف كيفية حل مشكلات التصميم المتكررة لتصميم برمجيات موجهة للكائنات مرنة وقابلة لإعادة الاستخدام، أي الكائنات التي يسهل تنفيذها وتغييرها واختبارها وإعادة استخدامها. [1]

ما هي المشاكل التي يمكن أن يحلها نمط تصميم الجسر؟ [2]

  • ينبغي تعريف التجريد وتنفيذه وتوسيع نطاقهما بشكل مستقل عن بعضهما البعض.
  • ينبغي تجنب الربط وقت التجميع بين التجريد وتنفيذه حتى يمكن تحديد التنفيذ في وقت التشغيل.

عند استخدام التصنيف الفرعي، تقوم الفئات الفرعية المختلفة بتنفيذ فئة مجردة بطرق مختلفة. ولكن التنفيذ مرتبط بالتجريد في وقت التجميع ولا يمكن تغييره في وقت التشغيل.

ما هو الحل الذي يصفه نمط تصميم الجسر؟

  • فصل التجريد ( Abstraction) عن تنفيذه ( Implementor) عن طريق وضعهما في تسلسلات هرمية منفصلة للفئة.
  • تنفيذ ذلك Abstractionمن حيث (التفويض إلى) Implementorالكائن.

يتيح لك هذا تكوين Abstractionكائن Implementorفي وقت التشغيل.
راجع أيضًا الرسم التخطيطي لفئة وتسلسل لغة النمذجة الموحدة أدناه.

بناء

مخطط فئة وتسلسل UML

مثال لفئة UML ومخطط التسلسل لنمط تصميم الجسر. [3]

في الرسم التخطيطي لفئة لغة النمذجة الموحدة أعلاه ، لا يتم تنفيذ التجريد ( Abstraction) كالمعتاد في تسلسل هرمي واحد للوراثة. بدلاً من ذلك، يوجد تسلسل هرمي واحد للتجريد ( Abstraction) وتسلسل هرمي منفصل لتنفيذه ( Implementor)، مما يجعل الاثنين مستقلين عن بعضهما البعض. يتم تنفيذ Abstractionالواجهة ( operation()) من حيث (عن طريق التفويض إلى) الواجهة Implementor( imp.operationImp()). يوضح الرسم التخطيطي لتسلسل UML
التفاعلات أثناء وقت التشغيل: يفوض الكائن التنفيذ إلى الكائن (عن طريق استدعاء ) ، والذي يقوم بإجراء العملية ويعود إلى . Abstraction1Implementor1operationImp()Implementor1Abstraction1

مخطط الفصل

التجريد (الفئة المجردة)
يحدد الواجهة المجردة
يحافظ على مرجع المنفذ.
RefinedAbstraction (الفئة العادية)
يمتد الواجهة المحددة بواسطة التجريد
المنفذ (الواجهة)
يحدد الواجهة لفئات التنفيذ
ConcreteImplementor (الفئة العادية)
تنفيذ واجهة المنفذ
جسر في LePUS3 (أسطورة)

مثال

سي شارب

يقوم نمط الجسر بتكوين الكائنات في بنية شجرية. وهو يفصل التجريد عن التنفيذ. هنا يمثل التجريد العميل الذي سيتم استدعاء الكائنات منه. فيما يلي مثال تم تنفيذه بلغة C#


// يساعد في توفير واجهة عامة للهندسة المعمارية المنفصلة حقًا IBridge { void Function1 (); void Function2 (); }  

     
     


public class Bridge1 : IBridge { public void Function1 () { Console .WriteLine ( "Bridge1.Function1" ) ; }    

      
    
        
    

    public void Function2 () { Console .WriteLine ( "Bridge1.Function2" ) ; } }  
    
        
    


public class Bridge2 : IBridge { public void Function1 () { Console .WriteLine ( "Bridge2.Function1" ) ; }    

      
    
        
    

    public void Function2 () { Console .WriteLine ( "Bridge2.Function2" ) ; } }  
    
        
    


الواجهة العامة IAbstractBridge { void CallMethod1 (); void CallMethod2 (); }  

     
     


الفئة العامة AbstractBridge : IAbstractBridge { جسر IBridge العام ؛    

      

    جسر عام AbstractBridge ( جسر IBridge ) { هذا .bridge = جسر ؛ }  
    
          
    

    public void CallMethod1 () { this . bridge . Function1 (); }  
    
        
    

    public void CallMethod2 () { this . bridge . Function2 (); } }  
    
        
    

فئات Bridge هي التنفيذ الذي يستخدم نفس البنية الموجهة للواجهة لإنشاء الكائنات. من ناحية أخرى، يأخذ التجريد مثيلًا لفئة التنفيذ ويشغل طريقتها. وبالتالي، يتم فصلهما تمامًا عن بعضهما البعض.

كريستال

فئة مجردة DrawingAPI 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 } - radius: #{ radius } " end end   
           
    
  


فئة مجردة ، الحصول على الشكل المحمي ، drawing_api : DrawingAPI  
      

  def initialize ( @drawing_api ) end 
  

  ملخص تعريف الرسم ملخص تعريف تغيير الحجم حسب النسبة المئوية ( النسبة المئوية : Float64 ) النهاية  
      


الفئة CircleShape < Shape getter x : Float64 getter y : Float64 getter radius : Float64   
     
     
     

  def initialize ( @x ، @y ، @radius ، drawing_api : DrawingAPI ) super ( drawing_api ) end      
    
  

  def draw @drawing_api . draw_circle ( @x , @y , @radius ) النهاية 
      
  

  def resize_by_percentage ( percent : Float64 ) @radius *= ( 1 + percent / 100 ) end end   
        
  


الفئة BridgePattern def self.test shapes = [ ] of Shape shapes << CircleShape.new ( 1.0 , 2.0 , 3.0 , DrawingAPI1.new ) shapes << CircleShape.new ( 5.0 , 7.0 , 11.0 , DrawingAPI2.new ) 
   
        
         
         

    الأشكال . كل منها تفعل | الشكل | الشكل . تغيير الحجم حسب النسبة المئوية ( 2.5 ) يضع الشكل . ارسم نهاية نهاية نهاية  
      
       
    
  


نمط الجسر . اختبار

الناتج

API1.circle عند 1.0:2.0 - نصف القطر: 3.075
API2.circle عند 5.0:7.0 - نصف القطر: 11.275

سي++

#تضمين <iostream> #تضمين <سلسلة> #تضمين <متجه> 
 
 


الفئة DrawingAPI { public : virtual ~ DrawingAPI () = default ; virtual std :: string DrawCircle ( float x , float y , float radius ) const = 0 ; };  
  
       
              


الفئة 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 ) + " - radius: " + std :: to_string ( radius ); } };     
  
             
              
           
    


الفئة 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 ) + " - radius: " + std :: to_string ( radius ); } };     
  
             
              
           
    


الفئة Shape { public : Shape ( const DrawingAPI & drawing_api ) : drawing_api_ ( drawing_api ) {} virtual ~ Shape () = default ;  
  
         
       

    افتراضي std :: string Draw () const = 0 ؛ افتراضي float ResizeByPercentage ( const float percent ) = 0 ؛     
          

  محمي : 
ثابت DrawingAPI & drawing_api_ ; };      


الفئة CircleShape : public Shape { public : CircleShape ( float x , float y , float radius , const DrawingAPI & drawing_api ) : Shape ( drawing_api ), x_ ( x ), y_ ( y ), radius_ ( radius ) {}    
      
            
           

    std :: string Draw () const override { return drawing_api_ . DrawCircle ( x_ , y_ , radius_ ); }    
           
    

    تعويم تغيير الحجم حسب النسبة المئوية ( نسبة ثابتة عائمة ) تجاوز { إرجاع نصف القطر *= ( 1.0f + النسبة المئوية / 100.0f ); } خاص : تعويم x_ ، y_ ، نصف القطر_ ؛ };     
           
    
  
  
       


int main ( int argc ، char ** argv ) { ثابت DrawingAPI01 api1 {}؛ ثابت DrawingAPI02 api2 {}؛ std :: متجه < شكل الدائرة > الأشكال { شكل الدائرة { 1.0f ، 2.0f ، 3.0f ، api1 شكل الدائرة { 5.0f ، 7.0f ، 11.0f ، api2 }      
    
    
    
       
       
   

  بالنسبة إلى ( auto & shape : shapes ) { shape.ResizeByPercentage ( 2.5 ) ؛ std :: cout << shape.Draw ( ) << std :: endl ؛ }    
    
        
  

  العودة 0 ؛ } 

الإخراج:

API01.circle عند 1.000000:2.000000 - نصف القطر: 3.075000
API02.circle عند 5.000000:7.000000 - نصف القطر: 11.275000

جافا

يقوم برنامج Java التالي بتعريف حساب بنكي يفصل عمليات الحساب عن تسجيل هذه العمليات.

// يحتوي Logger على تنفيذين: المعلومات والتحذير 
@FunctionalInterface 
interface  Logger { void log ( String message ); static Logger info () { return message -> System . out . println ( "info: " + message ); } static Logger warning () { return message -> System . out . println ( "warning: " + message ); } } 
      
    
       
             
    
       
             
    


ملخص الفئة AbstractAccount { private Logger logger = Logger.info (); public void setLogger ( Logger logger ) { this.logger = logger ; } // يتم تفويض جزء التسجيل إلى تنفيذ Logger protected void operate ( String message , boolean result ) { logger.log ( message + " result " + result ) ; } }   
        
    
        
          
    
    
    
          
            
    


class  SimpleAccount extends AbstractAccount { private int balance ; public SimpleAccount ( int balance ) { this.balance = balance ; } public boolean isBalanceLow () { return balance < 50 ; } public void pull ( int amount ) { boolean shouldPerform = balance > = amount ; if ( shouldPerform ) { balance -= amount ; } operate ( " withdraw" + amount , shouldPerform ); } }   
      
    
       
          
    
    
       
           
    
    
        
             
          
              
        
           
    


public class BridgeDemo { public static void main ( String [] args ) { SimpleAccount account = new SimpleAccount ( 100 ); account.draw ( 75 ) ; if ( count.isBalanceLow ( ) ) { // يمكنك أيضًا تغيير تنفيذ Logger في وقت التشغيل account.setLogger ( Logger.warning ( ) ) ; } account.draw ( 10 ) ; account.draw ( 100 ) ; } }   
         
            
        
        
          
            
            
        
        
        
        
    

سيتم إخراج:

المعلومات: سحب 75 نتيجة صحيحة
تحذير: سحب 10 نتيجة صحيحة
تحذير: سحب 100 نتيجة خاطئة

بي اتش بي

واجهة  DrawingAPI 
{ 
    دالة  drawCircle ( $x ،  $y ،  $radius 
}

 تطبق الفئة DrawingAPI1  DrawingAPI { public function drawCircle ( $x , $y , $radius ) { echo "API1.circle at $x : $y radius $radius . \n " ; } } 

        
    
         
    


 تطبق الفئة DrawingAPI2  DrawingAPI { public function drawCircle ( $x , $y , $radius ) { echo "API2.circle at $x : $y radius $radius . \n " ; } } 

        
    
         
    


 الفئة  المجردة Shape 
{ 
    محمية  $drawingAPI ؛

     دالة مجردة  عامة draw (); دالة مجردة عامة resizeByPercentage ( $pct ); 
       

     وظيفة  محمية __construct ( DrawingAPI  $drawingAPI ) 
    { 
        $this -> drawingAPI  =  $drawingAPI ؛ 
    } 
}

الفئة  CircleShape  تمتد إلى  Shape 
{ 
    private  $x ؛ 
    private  $y ؛ 
    private  $radius ؛

     دالة  عامة __construct ( $x ،  $y ،  $radius ،  DrawingAPI  $drawingAPI ) 
    { 
        الأصل :: __construct ( $drawingAPI 
        $this -> x  =  $x ؛ 
        $this -> y  =  $y ؛ 
        $this -> radius  =  $radius ؛ 
    }

     دالة  عامة draw () 
    { 
        $this -> drawingAPI -> drawCircle ( $this -> x ،  $this -> y ،  $this -> radius ); 
    }

     دالة  عامة resizeByPercentage ( $pct ) 
    { 
        $this -> radius  *=  $pct ؛ 
    } 
}

الفئة  Tester 
{ 
    public  static  function  main () 
    { 
        $shapes  =  array ( 
            new  CircleShape ( 1 ,  3 ,  7 ,   new  DrawingAPI1 ()), 
            new  CircleShape ( 5 ,  7 ,  11 ,  new  DrawingAPI2 ()), 
        );

        لكل  ( $shapes  كـ  $shape )  { 
            $shape -> تغيير الحجم حسب النسبة المئوية ( 2.5 ); 
            $shape -> رسم (); 
        } 
    } 
}

المُختبر :: الرئيسي ();

الإخراج:

API1.circle عند دائرة نصف قطرها 1:3 17.5
API2.circle عند دائرة نصف قطرها 5:7 27.5

سكالا

سمة DrawingAPI { def drawCircle ( x : Double , y : Double , radius : Double ) }  
        


الفئة DrawingAPI1 تمتد إلى DrawingAPI { def drawCircle ( x : Double , y : Double , radius : Double ) = println ( s"API #1 $ x $ y $ radius " ) }    
            


الفئة DrawingAPI2 تمتد إلى DrawingAPI { def drawCircle ( x : Double , y : Double , radius : Double ) = println ( s"API #2 $ x $ y $ radius " ) }    
            


الفئة المجردة Shape ( drawingAPI : DrawingAPI ) { def draw () def resizePercentage ( pct : Double ) }    
   
    


الفئة CircleShape ( x : Double ، y : Double ، var radius : Double ، drawingAPI : DrawingAPI ) تمتد إلى Shape ( drawingAPI : DrawingAPI ) {         
       

  def draw () = drawingAPI . drawCircle ( x ، y ، نصف القطر )     

  def resizePercentage ( pct : Double ) { نصف القطر *= pct } }       


كائن BridgePattern { def main ( args : Array [ String ]) { Seq ( شكل دائرة جديد ( 1 ، 3 ، 5 ، واجهة رسم API1 جديدة شكل دائرة جديد ( 4 ، 5 ، 6 ، واجهة رسم API2 جديدة ) ) foreach { x => x . resizePercentage ( 3 ) x . draw ( ) } }  
     
     
	     
	     
        
        
        			
      	
  

بايثون

""" 
مثال على نمط الجسر. 
""" 
من  abc  استيراد  ABCMeta ،  الطريقة المجردة


NOT_IMPLEMENTED  =  "ينبغي عليك تنفيذ هذا."


الفئة  DrawingAPI : 
    __metaclass__  =  ABCMeta

    @abstractmethod 
    def  draw_circle ( self ,  x ,  y ,  radius ): 
        raise  NotImplementedError ( NOT_IMPLEMENTED )


الفئة  DrawingAPI1 ( DrawingAPI ): 
    def  draw_circle ( self ,  x ,  y ,  radius ): 
        إرجاع  f "API1.circle at { x } : { y } - radius: { radius } "


الفئة  DrawingAPI2 ( DrawingAPI ): 
    def  draw_circle ( self ،  x ،  y ،  radius ): 
        إرجاع  f "API2.circle عند { x } : { y } - نصف القطر: { نصف القطر } "


الفئة  DrawingAPI3 ( DrawingAPI ): 
    def  draw_circle ( self ،  x ،  y ،  radius ): 
        إرجاع  f "API3.circle عند { x } : { y } - نصف القطر: { نصف القطر } "


الصف  الشكل : 
    __metaclass__  =  ABCMeta

    drawing_api  =  None 
    def  __init__ ( self ،  drawing_api ) : 
        self.drawing_api = drawing_api  

    @abstractmethod 
    def  draw ( self ): 
        raise  NotImplementedError ( NOT_IMPLEMENTED )

    @abstractmethod 
    def  resize_by_percentage ( self ,  percent ): 
        raise  NotImplementedError ( NOT_IMPLEMENTED )


class  CircleShape ( Shape ) : 
    def  __init __ ( self ,  x ,  y ,  radius ,  drawing_api ) : 
        self.x = x self.y = y self.radius = radius super ( CircleShape , self ) .__ init __ ( drawing_api )  
          
          
         


    def  draw ( self ) : 
        return  self.draw_api.draw_circle ( self.x , self.y , self.radius )  

    def  resize_by_percentage ( self ,  percent ): 
        self . radius  *=  1  +  percent  /  100


الفئة  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 ()), 
        ]

        للشكل  في الأشكال : الشكل . تغيير الحجم حسب النسبة المئوية ( 2.5  ) طباعة ( الشكل . رسم ( )) 
            
            


BridgePattern . اختبار ()

انظر أيضا

مراجع

  1. ^ ab Gamma, Erich ; Helm, Richard; Johnson, Ralph ; Vlissides, John (1994). أنماط التصميم: عناصر البرامج الموجهة للكائنات القابلة لإعادة الاستخدام . Addison-Wesley. ص. 151. ISBN 0-201-63361-2.
  2. ^ "نمط تصميم الجسر - المشكلة والحل وإمكانية التطبيق". w3sDesign.com . تم الاسترجاع في 12 أغسطس 2017 .
  3. ^ "نمط تصميم الجسر - البنية والتعاون". w3sDesign.com . تم الاسترجاع في 2017-08-12 .
  • جسر في UML وفي LePUS3 (لغة نمذجة رسمية)
  • أنماط تصميم C#: نمط الجسر. 2002-12-20. {{cite book}}: |work=تم تجاهله ( مساعدة ) من: James W. Cooper (2003). أنماط تصميم C#: برنامج تعليمي. Addison-Wesley . ISBN 0-201-84453-2.
تم الاسترجاع من "https://en.wikipedia.org/w/index.php?title=نمط_الجسر&oldid=1183383676"
Original text
Rate this translation
Your feedback will be used to help improve Google Translate