กลับไปหน้าบทความ

อ่าน 11 นาที

รูปแบบสะพาน

รูป แบบบริดจ์ เป็น รูปแบบการออกแบบ ที่ใช้ใน วิศวกรรมซอฟต์แวร์ ซึ่งมีจุดประสงค์เพื่อ "แยก นามธรรม ออก จาก การใช้งาน เพื่อให้ทั้งสองสามารถเปลี่ยนแปลงได้อย่างอิสระ" ซึ่งนำเสนอโดย...

รูปแบบสะพาน

รูปแบบบริดจ์เป็นรูปแบบการออกแบบที่ใช้ในวิศวกรรมซอฟต์แวร์ซึ่งมีจุดประสงค์เพื่อ"แยกนามธรรม ออก จากการใช้งานเพื่อให้ทั้งสองสามารถเปลี่ยนแปลงได้อย่างอิสระ"ซึ่งนำเสนอโดยกลุ่ม Gang of Four [ 1 ] บริดจ์ใช้การห่อหุ้มการรวมกลุ่มและสามารถใช้การสืบทอดเพื่อแยกความรับผิดชอบออกเป็นคลาสต่างๆ

เมื่อคลาสมีการเปลี่ยนแปลงบ่อย คุณสมบัติของการเขียนโปรแกรมเชิงวัตถุจะมีความเป็นประโยชน์อย่างมาก เพราะ สามารถแก้ไข โค้ดของโปรแกรมได้ง่ายโดยมีความรู้เกี่ยวกับโปรแกรมเพียงเล็กน้อย รูปแบบบริดจ์มีประโยชน์เมื่อทั้งคลาสและสิ่งที่คลาสทำมีการเปลี่ยนแปลงบ่อย คลาสเองสามารถคิดได้ว่าเป็นนามธรรมและสิ่งที่คลาสสามารถทำได้คือการใช้งานรูปแบบบริดจ์ยังสามารถคิดได้ว่าเป็นนามธรรมสองชั้นอีกด้วย

เมื่อมีการกำหนดวิธีการใช้งานตายตัวเพียงวิธีเดียว รูปแบบนี้จะเรียกว่า สำนวน Pimplในโลก ของภาษา C++

รูปแบบบริดจ์มักถูกเข้าใจผิดว่าเป็นรูปแบบอะแดปเตอร์และมักถูกนำไปใช้โดยใช้รูปแบบอะแดปเตอร์แบบอ็อบเจ็กต์เช่น ในโค้ด Java ด้านล่างนี้

ทางเลือกอื่น: การใช้งานสามารถแยกส่วนได้มากขึ้นไปอีกโดยการเลื่อนการใช้งานไปจนถึงจุดที่ใช้แนวคิดนามธรรม

ภาพรวม

รูปแบบการออกแบบ Bridge เป็นหนึ่งใน 23 รูปแบบการออกแบบ GoF ที่รู้จักกันดี ซึ่งอธิบายวิธีการแก้ปัญหาการออกแบบที่เกิดขึ้นซ้ำๆ เพื่อออกแบบซอฟต์แวร์เชิงวัตถุที่มีความยืดหยุ่นและนำกลับมาใช้ใหม่ได้ กล่าวคือ วัตถุที่ง่ายต่อการใช้งาน เปลี่ยนแปลง ทดสอบ และนำกลับมาใช้ใหม่[ 1 ]

รูปแบบการออกแบบ Bridge สามารถแก้ปัญหาอะไรได้บ้าง? [ 2 ]

  • แนวคิดเชิงนามธรรมและการนำไปใช้ควรได้รับการกำหนดและพัฒนาอย่างอิสระจากกัน
  • ควรหลีกเลี่ยงการผูกมัดระหว่างนามธรรมและการนำไปใช้งานในขั้นตอนการคอมไพล์ เพื่อให้สามารถเลือกการนำไปใช้งานได้ในขั้นตอนการรันไทม์

เมื่อใช้การสร้างคลาสย่อย คลาสย่อยแต่ละคลาสจะนำคลาสแบบนามธรรมมาใช้ในรูปแบบที่แตกต่างกัน แต่การใช้งานจะถูกผูกไว้กับนามธรรมตั้งแต่ขั้นตอนการคอมไพล์ และไม่สามารถเปลี่ยนแปลงได้ในระหว่างการทำงานของโปรแกรม

รูปแบบการออกแบบ Bridge อธิบายถึงวิธีการแก้ปัญหาแบบใด?

  • แยกนามธรรม ( Abstraction) ออกจากการใช้งาน ( Implementor) โดยการใส่ไว้ในลำดับชั้นของคลาสที่แยกจากกัน
  • ดำเนินการAbstractionตามนั้นโดย (มอบหมายให้) Implementorวัตถุ หนึ่งๆ

วิธีนี้ช่วยให้สามารถกำหนดค่าAbstractionด้วยImplementorอ็อบเจ็กต์ในระหว่างการทำงานได้ โปรดดู แผนภาพคลาสและลำดับ ของ Unified Modeling Language ด้านล่าง ด้วย

โครงสร้าง

แผนภาพคลาสและลำดับ UML

ตัวอย่างคลาส UML และไดอะแกรมลำดับสำหรับรูปแบบการออกแบบ Bridge [ 3 ]

ในแผนภาพคลาส Unified Modeling Language ข้างต้น นามธรรม ( Abstraction) ไม่ได้ถูกนำไปใช้ตามปกติในลำดับชั้นการสืบทอดเดียว แต่จะมีลำดับชั้นหนึ่งสำหรับนามธรรม ( Abstraction) และลำดับชั้นแยกต่างหากสำหรับการใช้งาน ( Implementor) ซึ่งทำให้ทั้งสองเป็นอิสระจากกัน อินเทอ ร์Abstractionเฟซ ( operation()) ถูกนำไปใช้ในแง่ของ (โดยการมอบหมายไปยัง) อินImplementorเทอร์เฟซ ( imp.operationImp()) แผนภาพลำดับ UML แสดงปฏิสัมพันธ์ในขณะรันไทม์: อ็อบเจ็กต์มอบหมายการใช้งานให้กับอ็อบเจ็กต์(โดยการเรียกใช้) ซึ่งดำเนินการและส่งกลับไปยัง Abstraction1Implementor1operationImp()Implementor1Abstraction1

แผนภาพคลาส

นามธรรม (คลาสแบบนามธรรม)
กำหนดอินเทอร์เฟซนามธรรม
รักษาการอ้างอิงของผู้ดำเนินการไว้
การลดทอนแบบละเอียด (คลาสปกติ)
ขยายอินเทอร์เฟซที่กำหนดโดยนามธรรม
ผู้ดำเนินการ (อินเทอร์เฟซ)
กำหนดอินเทอร์เฟซสำหรับคลาสการใช้งาน
ผู้ดำเนินการคอนกรีต (คลาสปกติ)
ใช้งานอินเทอร์เฟซ Implementor
สะพานในLePUS3 ( คำอธิบาย )

ตัวอย่าง

ซี#

รูปแบบ Bridge pattern ประกอบวัตถุเข้าด้วยกันในโครงสร้างแบบต้นไม้ โดยแยกส่วนที่เป็นนามธรรมออกจากส่วนการใช้งานจริง ในที่นี้ นามธรรมหมายถึงไคลเอ็นต์ที่จะเรียกใช้วัตถุ ตัวอย่างการใช้งานในภาษา C# แสดงอยู่ด้านล่าง

เนมสเปซWikipedia.Examples ;โดยใช้ระบบ;// ช่วยให้มีสถาปัตยกรรมที่แยกส่วนอย่างแท้จริงinterface IBridge { void Function1 (); void Function2 (); }class Bridge1 : IBridge { public void Function1 () { Console . WriteLine ( "Bridge1.Function1" ); }public void Function2 () { Console . WriteLine ( "Bridge1.Function2" ); } }class Bridge2 : IBridge { public void Function1 () { Console . WriteLine ( "Bridge2.Function1" ); }public void Function2 () { Console . WriteLine ( "Bridge2.Function2" ); } }อินเทอร์เฟซIAbstractBridge { CallMethod1 เป็นโมฆะ(); เป็นโมฆะCallMethod2 (); }คลาสAbstractBridge : IAbstractBridge { public IBridge bridge ;public AbstractBridge ( IBridge bridge ) { this . bridge = bridge ; }public void CallMethod1 () { this . bridge . Function1 (); }public void CallMethod2 () { this . bridge . Function2 (); } }

คลาส Bridge คือการใช้งานจริงที่ใช้สถาปัตยกรรมแบบอินเทอร์เฟซเดียวกันในการสร้างอ็อบเจ็กต์ ในทางกลับกัน คลาส Abstraction จะรับอินสแตนซ์ของคลาสที่ใช้งานจริงและเรียกใช้เมธอดของมัน ดังนั้น ทั้งสองจึงแยกออกจากกันอย่างสิ้นเชิง

คริสตัล

คลาสDrawingAPI นามธรรมdef draw_circle ( x : Float64 , y : Float64 , radius : Float64 ) endclass DrawingAPI1 < DrawingAPI def draw_circle ( x : Float , y : Float , radius : Float ) "API1.circle at #{ x } : #{ y } - radius: #{ radius } " end endclass DrawingAPI2 < DrawingAPI def draw_circle ( x : Float64 , y : Float64 , radius : Float64 ) "API2.circle at #{ x } : #{ y } - radius: #{ radius } " end endคลาสแบบนามธรรมShape protected getter drawing_api : DrawingAPIdef initialize ( @drawing_api ) endนิยามนามธรรมวาด นิยาม นามธรรมปรับขนาดตามเปอร์เซ็นต์( เปอร์เซ็นต์: Float64 ) สิ้นสุดคลาสCircleShape < Shape getter x : Float64 getter y : Float64 getter radius : Float64def initialize ( @x , @y , @radius , drawing_api : DrawingAPI ) super ( drawing_api ) enddef draw @ drawing_api.draw_circle ( @x , @y , @radius ) enddef resize_by_percentage ( percent : Float64 ) @radius *= ( 1 + percent / 100 ) end endclass 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 )shapes . each do | shape | shape . resize_by_percentage ( 2.5 ) puts shape . draw end end endBridgePattern . test

เอาต์พุต

API1.วงกลมที่ 1.0:2.0 - รัศมี: 3.075 API2.วงกลมที่ 5.0:7.0 - รัศมี: 11.275 

ซี++

import std ;using std :: string ; using std :: vector ;class DrawingAPI { public : virtual ~ DrawingAPI () = default ; virtual string drawCircle ( float x , float y , float radius ) const = 0 ; };class DrawingAPI01 : public DrawingAPI { public : [[ nodiscard ]] string drawCircle ( float x , float y , float radius ) const override { return std :: format ( "API01.circle at {}:{} - radius: {}" , x , y , radius ); } };class DrawingAPI02 : public DrawingAPI { public : [[ nodiscard ]] string drawCircle ( float x , float y , float radius ) const override { return std :: format ( "API02.circle at {}:{} - radius: {}" , x , y , radius ); } };คลาสShape { protected : const DrawingAPI & drawingApi ; public : Shape ( const DrawingAPI & api ) : drawingApi { api } {} }เสมือน~ รูปร่าง() = ค่าเริ่มต้น;virtual string draw () const = 0 ; virtual float resizeByPercentage ( const float percent ) noexcept = 0 ; };คลาสCircleShape : public Shape { private : float x ; float y ; float radius ; public : CircleShape ( const DrawingAPI & api , float x , float y , float radius ) : Shape ( api ), x { x }, y { y }, radius { radius } {} }[[ nodiscard ]] string draw () const override { return drawingApi . drawCircle ( x , y , radius ); }[[ nodiscard ]] float resizeByPercentage ( float percent ) noexcept override { return radius *= ( 1.0f + percent / 100.0f ); } };int main ( int argc , char * argv []) { const DrawingAPI01 api1 ; const DrawingAPI02 api2 ; vector < CircleShape > shapes { CircleShape { api1 , 1.0f , 2.0f , 3.0f }, CircleShape { api2 , 5.0f , 7.0f , 11.0f } };สำหรับ( CircleShape & shape : shapes ) { shape.resizeByPercentage ( 2.5 ); std :: println ( " { }" , shape.draw ( ) ) ; }ส่งคืนค่า0 ; }

ผลลัพธ์:

API01.วงกลมที่พิกัด 1.000000:2.000000 - รัศมี: 3.075000 API02.วงกลมที่พิกัด 5.000000:7.000000 - รัศมี: 11.275000 

โค้ดนี้ต้องการคอมไพเลอร์ที่รองรับ C++23 ตัวอย่างเช่น บน Ubuntu 26.06 LTS ที่ใช้ g++-15 จะต้องทำการคอมไพล์แบบ 2 ขั้นตอนดังต่อไปนี้:

g++-15 -std=c++23 -c -fmodules -fmodule-only -fsearch-include-path bits/std.cc g++-15 -std=c++23 -fmodules -o program program.cpp 

ชวา

โปรแกรม Javaต่อไปนี้กำหนดบัญชีธนาคารที่แยกการดำเนินการทางบัญชีออกจากการบันทึกการดำเนินการเหล่านั้น

แพ็คเกจorg.wikipedia.examples ;// Logger มีการใช้งานสองแบบ: info และ warning @FunctionalInterface interface Logger { void log ( String message ); static Logger info () { return message -> System . out . printf ( "info: %s%n" , message ); } static Logger warning () { return message -> System . out . printf ( "warning: %s%n" , 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 ( String.format ( " % s result %s " , message , result ) ) ; } }คลาสSimpleAccount สืบทอดมาจาก AbstractAccount { private int balance ; public SimpleAccount ( int balance ) { this . balance = balance ; } public boolean isBalanceLow () { return balance < 50 ; } public void withdraw ( int amount ) { boolean shouldPerform = balance >= amount ; if ( shouldPerform ) { balance -= amount ; } operate ( String . format ( "withdraw %s" , amount , shouldPerform )); } }public class BridgeDemo { public static void main ( String [] args ) { SimpleAccount account = new SimpleAccount ( 100 ); account . withdraw ( 75 ); if ( account . isBalanceLow ()) { // คุณสามารถเปลี่ยนการใช้งาน Logger ในขณะรันไทม์ได้account . setLogger ( Logger . warning ()); } account . withdraw ( 10 ); account . withdraw ( 100 ); } }

ผลลัพธ์ที่ได้จะเป็นดังนี้:

ข้อมูล: ถอน 75 ผลลัพธ์ถูกต้อง คำเตือน: ถอน 10 ผลลัพธ์ถูกต้อง คำเตือน: ถอน 100 ผลลัพธ์ไม่ถูกต้อง 

พีพี

interface DrawingAPI { function drawCircle ( $x , $y , $radius ); }คลาสDrawingAPI1 implements DrawingAPI { public function drawCircle ( $x , $y , $radius ) { echo "API1.circle at $x : $y radius $radius . \n " ; } }คลาสDrawingAPI2 implements DrawingAPI { public function drawCircle ( $x , $y , $radius ) { echo "API2.circle at $x : $y radius $radius . \n " ; } }คลาสนามธรรมShape { protected $drawingAPI ;ฟังก์ชันนามธรรมสาธารณะdraw (); ฟังก์ชันนามธรรมสาธารณะresizeByPercentage ( $pct );protected function __construct ( DrawingAPI $drawingAPI ) { $this -> drawingAPI = $drawingAPI ; } }class CircleShape extends Shape { private $x ; private $y ; private $radius ;public function __construct ( $x , $y , $radius , DrawingAPI $drawingAPI ) { parent :: __construct ( $drawingAPI ); $this -> x = $x ; $this -> y = $y ; $this -> radius = $radius ; }public function draw () { $this -> drawingAPI -> drawCircle ( $this -> x , $this -> y , $this -> radius ); }public function 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 ()), );foreach ( $shapes as $shape ) { $shape -> resizeByPercentage ( 2.5 ); $shape -> draw (); } } }Tester :: main ();

ผลลัพธ์:

API1.วงกลมที่อัตราส่วน 1:3 รัศมี 17.5 API2.วงกลมที่อัตราส่วน 5:7 รัศมี 27.5 

สกาล่า

trait 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 " ) }class DrawingAPI2 extends 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 ) }class CircleShape ( x : Double , y : Double , var radius : Double , drawingAPI : DrawingAPI ) extends Shape ( drawingAPI : DrawingAPI ) {def draw ( ) = drawingAPI.drawCircle ( x , y , radius )def resizePercentage ( pct : Double ) { radius *= pct } }object BridgePattern { def main ( args : Array [ String ]) { Seq ( new CircleShape ( 1 , 3 , 5 , new DrawingAPI1 ), new CircleShape ( 4 , 5 , 6 , new DrawingAPI2 ) ) foreach { x => x . resizePercentage ( 3 ) x . draw () } } }

ไพธอน

""" ตัวอย่างรูปแบบสะพาน""" จากabc นำเข้าABCMeta , abstractmethod จากtyping นำเข้าNoReturnยังไม่ได้ดำเนินการ: str = "คุณควรดำเนินการส่วนนี้"คลาสDrawingAPI : __metaclass__ = ABCMeta@abstractmethod def draw_circle ( self , x : float , y : float , radius : float ) -> NoReturn : raise NotImplementedError ( NOT_IMPLEMENTED )คลาสDrawingAPI1 ( DrawingAPI ): def draw_circle ( self , x : float , y : float , radius : float ) -> str : return f "API1.circle at { x } : { y } - radius: { radius } "คลาสDrawingAPI2 ( DrawingAPI ): def draw_circle ( self , x : float , y : float , radius : float ) -> str : return f "API2.circle at { x } : { y } - radius: { radius } "คลาสDrawingAPI3 ( DrawingAPI ): def draw_circle ( self , x : float , y : float , radius : float ) -> str : return f "API3.circle ที่{ x } : { y } - รัศมี: { radius } "คลาสShape : __metaclass__ = ABCMetadrawing_api : DrawingAPI = None def __init__ ( self , drawing_api : DrawingAPI ) -> None : self . drawing_api = drawing_api@abstractmethod def draw ( self ) -> NoReturn : raise NotImplementedError ( NOT_IMPLEMENTED )@abstractmethod def resize_by_percentage ( self , percent : float ) -> NoReturn : raise NotImplementedError ( NOT_IMPLEMENTED )class CircleShape ( Shape ): def __init__ ( self , x : float , y : float , radius : float , drawing_api : DrawingAPI ): self . x = x self . y = y self . radius = radius super ( CircleShape , self ) . __init__ ( drawing_api )def draw ( self ) - > str : return self.drawing_api.draw_circle ( self.x , self.y , self.radius )def resize_by_percentage ( self , percent : float ) -> None : self . radius *= 1 + percent / 100class BridgePattern : @staticmethod def test () -> None : shapes : list [ CircleShape ] = [ 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 ) พิมพ์( รูปร่าง. วาด())ถ้า__name__ == "__main__" : BridgePattern . test ()

ดูเพิ่มเติม

  • เชื่อมโยงใน UML และใน LePUS3 (ภาษาสร้างแบบจำลองเชิงทางการ)
  • รูปแบบการออกแบบในภาษา C#: รูปแบบบริดจ์จาก: James W. Cooper (2003). รูปแบบการออกแบบในภาษา C#: คู่มือ . Addison-Wesley . ISBN 0-201-84453-2.
ดึงข้อมูลมาจาก " https://en.wikipedia.org/w/index.php?title=Bridge_pattern&oldid=1352638337 "

สรุปเนื้อหา

ข้อมูลสำคัญจากบทความ

ข้อมูลสำคัญเกี่ยวกับ รูปแบบสะพาน

รูป แบบบริดจ์ เป็น รูปแบบการออกแบบ ที่ใช้ใน วิศวกรรมซอฟต์แวร์ ซึ่งมีจุดประสงค์เพื่อ "แยก นามธรรม ออก จาก การใช้งาน เพื่อให้ทั้งสองสามารถเปลี่ยนแปลงได้อย่างอิสระ" ซึ่งนำเสนอโดย...

ภาพรวม

รูปแบบการออกแบบ Bridge เป็นหนึ่งใน 23 รูปแบบการออกแบบ GoF ที่รู้จักกันดี ซึ่งอธิบายวิธีการแก้ปัญหาการออกแบบที่เกิดขึ้นซ้ำๆ เพื่อออกแบบซอฟต์แวร์เชิงวัตถุที่มีความยืดหยุ่นและนำกลับมาใช้ใหม่ได้ กล่าวคือ วัตถุที่ง่ายต่อการใช้งาน เปลี่ยนแปลง ทดสอบ...

แผนภาพคลาสและลำดับ UML

ใน แผนภาพคลาส Unified Modeling Language ข้างต้น นามธรรม ( Abstraction ) ไม่ได้ถูกนำไปใช้ตามปกติในลำดับชั้นการสืบทอดเดียว แต่จะมีลำดับชั้นหนึ่งสำหรับนามธรรม ( Abstraction ) และลำดับชั้นแยกต่างหากสำหรับการใช้งาน ( Implementor ) ซึ่งทำให้ทั้งสองเป็นอิสระจากกัน...

ซี#

รูปแบบ Bridge pattern ประกอบวัตถุเข้าด้วยกันในโครงสร้างแบบต้นไม้ โดยแยกส่วนที่เป็นนามธรรมออกจากส่วนการใช้งานจริง ในที่นี้ นามธรรมหมายถึงไคลเอ็นต์ที่จะเรียกใช้วัตถุ ตัวอย่างการใช้งานในภาษา C# แสดงอยู่ด้านล่าง