نمط الجسر
نمط الجسر هو نمط تصميم يستخدم في هندسة البرمجيات ويهدف إلى "فصل التجريد عن تنفيذه بحيث يمكن للاثنين أن يختلفا بشكل مستقل" ، وقد قدمه Gang of Four . [1] يستخدم الجسر التغليف والتجميع ويمكنه استخدام الميراث لفصل المسؤوليات إلى فئات مختلفة .
عندما تتنوع الفئة بشكل متكرر، تصبح ميزات البرمجة الموجهة للكائنات مفيدة للغاية لأنه يمكن إجراء تغييرات على كود البرنامج بسهولة مع الحد الأدنى من المعرفة المسبقة بالبرنامج. يكون نمط الجسر مفيدًا عندما تتنوع الفئة وما تفعله بشكل متكرر. يمكن اعتبار الفئة نفسها بمثابة التجريد وما يمكن للفئة فعله باعتباره التنفيذ . يمكن أيضًا اعتبار نمط الجسر بمثابة طبقتين من التجريد.
عندما يكون هناك تنفيذ ثابت واحد فقط، يُعرف هذا النمط باسم مصطلح Pimpl في عالم C++ .
غالبًا ما يتم الخلط بين نمط الجسر ونمط المحول ، وغالبًا ما يتم تنفيذه باستخدام نمط محول الكائن ؛ على سبيل المثال، في كود Java أدناه.
متغير: يمكن فصل التنفيذ بشكل أكبر عن طريق تأجيل وجود التنفيذ إلى النقطة التي يتم فيها استخدام التجريد.
ملخص
نمط تصميم الجسر هو أحد أنماط تصميم GoF الثلاثة والعشرين المعروفة التي تصف كيفية حل مشكلات التصميم المتكررة لتصميم برمجيات موجهة للكائنات مرنة وقابلة لإعادة الاستخدام، أي الكائنات التي يسهل تنفيذها وتغييرها واختبارها وإعادة استخدامها. [1]
ما هي المشاكل التي يمكن أن يحلها نمط تصميم الجسر؟ [2]
- ينبغي تعريف التجريد وتنفيذه وتوسيع نطاقهما بشكل مستقل عن بعضهما البعض.
- ينبغي تجنب الربط وقت التجميع بين التجريد وتنفيذه حتى يمكن تحديد التنفيذ في وقت التشغيل.
عند استخدام التصنيف الفرعي، تقوم الفئات الفرعية المختلفة بتنفيذ فئة مجردة بطرق مختلفة. ولكن التنفيذ مرتبط بالتجريد في وقت التجميع ولا يمكن تغييره في وقت التشغيل.
ما هو الحل الذي يصفه نمط تصميم الجسر؟
- فصل التجريد (
Abstraction) عن تنفيذه (Implementor) عن طريق وضعهما في تسلسلات هرمية منفصلة للفئة. - تنفيذ ذلك
Abstractionمن حيث (التفويض إلى)Implementorالكائن.
يتيح لك هذا تكوين Abstractionكائن Implementorفي وقت التشغيل.
راجع أيضًا الرسم التخطيطي لفئة وتسلسل
لغة النمذجة الموحدة أدناه.
بناء
مخطط فئة وتسلسل UML

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

مثال
سي شارب
يقوم نمط الجسر بتكوين الكائنات في بنية شجرية. وهو يفصل التجريد عن التنفيذ. هنا يمثل التجريد العميل الذي سيتم استدعاء الكائنات منه. فيما يلي مثال تم تنفيذه بلغة 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 . اختبار ()
انظر أيضا
مراجع
- ^ ab Gamma, Erich ; Helm, Richard; Johnson, Ralph ; Vlissides, John (1994). أنماط التصميم: عناصر البرامج الموجهة للكائنات القابلة لإعادة الاستخدام . Addison-Wesley. ص. 151. ISBN 0-201-63361-2.
- ^ "نمط تصميم الجسر - المشكلة والحل وإمكانية التطبيق". w3sDesign.com . تم الاسترجاع في 12 أغسطس 2017 .
- ^ "نمط تصميم الجسر - البنية والتعاون". 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.
