คุณใช้รูปแบบบริดจ์เมื่อใด มันแตกต่างจากรูปแบบของอะแดปเตอร์อย่างไร


154

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


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

หนังสือ GoFตอบคำถามนี้โดยตรง
jaco0646

คำตอบ:


76

ตัวอย่างคลาสสิกของรูปแบบบริดจ์ใช้ในการกำหนดรูปร่างในสภาพแวดล้อม UI (ดูรายการ Wikipedia ของรูปแบบบริดจ์ ) รูปแบบสะพานเป็นคอมโพสิตของแม่แบบและกลยุทธ์รูปแบบ

มันเป็นมุมมองทั่วไปบางประการของรูปแบบตัวแปลงในรูปแบบบริดจ์ อย่างไรก็ตามการอ้างอิงจากบทความนี้ :

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


1
Bridge ไม่มีส่วนเกี่ยวข้องกับเทมเพลตหรือกลยุทธ์ สะพานเป็นรูปแบบโครงสร้าง แม่แบบและกลยุทธ์เป็นรูปแบบพฤติกรรม
jaco0646

249

มีการรวมกันของคำตอบของFedericoและจอห์น

เมื่อไหร่:

                   ----Shape---
                  /            \
         Rectangle              Circle
        /         \            /      \
BlueRectangle  RedRectangle BlueCircle RedCircle

Refactor ถึง:

          ----Shape---                        Color
         /            \                       /   \
Rectangle(Color)   Circle(Color)           Blue   Red

6
ทำไมคุณถึงทำมรดกสำหรับสี?
vainolo

10
@vainolo เพราะ Color เป็นส่วนต่อประสานและน้ำเงิน, แดงเป็นสีคอนกรีต
Weltschmerz

3
นี่เป็นเพียงการปรับปรุง ความตั้งใจของรูปแบบสะพาน: "แยกสิ่งที่เป็นนามธรรมออกจากการปฏิบัติเพื่อให้ทั้งสองสามารถเปลี่ยนแปลงได้อย่างอิสระ" สิ่งที่เป็นนามธรรมและการดำเนินการอยู่ที่นี่?
clapas

1
ไม่ใช่สี่เหลี่ยมผืนผ้า (สี) ที่เป็นนามธรรมมากกว่าสิ่งที่ BlueRectangle
Anton Shchastnyi

2
@clapas Abstraction คือ "Shape.color" ของคุณสมบัติดังนั้นคลาสสีแดงและคลาส Blue คือการนำไปใช้และส่วนต่อประสานสีคือบริดจ์
reco

230

รูปแบบสะพานเป็นแอปพลิเคชั่นของคำแนะนำแบบเก่า "ชอบองค์ประกอบมากกว่าการสืบทอด" มันจะมีประโยชน์เมื่อคุณต้อง subclass เวลาที่แตกต่างในรูปแบบที่เป็นมุมฉากกับคนอื่น สมมติว่าคุณต้องใช้ลำดับชั้นของรูปร่างที่มีสี คุณจะไม่รูปร่างย่อยด้วยสี่เหลี่ยมผืนผ้าและวงกลมจากนั้นสี่เหลี่ยมผืนผ้าย่อยด้วย RedRectangle, BlueRectangle และ GreenRectangle เหมือนกันสำหรับ Circle คุณจะได้ไหม คุณต้องการบอกว่าแต่ละ Shape มีสีและใช้ลำดับชั้นของสีและนั่นคือรูปแบบบริดจ์ ฉันจะไม่ใช้ "ลำดับชั้นของสี" แต่คุณได้รับแนวคิด ...


1
ดูแผนภาพ Anton Shchastnyi ด้านล่างสำหรับภาพประกอบกราฟิกของคำอธิบายนี้
NomadeNumerique

2
ฉันไม่คิดว่าสีเป็นตัวอย่างที่ดีสำหรับลำดับชั้นการนำไปปฏิบัติมันค่อนข้างสับสน มีตัวอย่างที่ดีของรูปแบบบริดจ์ใน "รูปแบบการออกแบบ" โดย GoF ซึ่งการใช้งานขึ้นอยู่กับแพลตฟอร์ม: PM ของ IBM, X ของ UNIX และอื่น ๆ
clapas

215

เมื่อไหร่:

        A
     /     \
    Aa      Ab
   / \     /  \
 Aa1 Aa2  Ab1 Ab2

Refactor ถึง:

     A         N
  /     \     / \
Aa(N) Ab(N)  1   2

3
ฉันคิดว่ามันเป็นวิธีปฏิบัติอย่างมากในการออกแบบ: 1) อธิบายการออกแบบตรงไปตรงมาที่ไม่ดี 2) การออกแบบ refactor / รหัสให้ดีขึ้น
factey Alexey

1
ใช้แนวคิดทางคณิตศาสตร์เพื่ออธิบายรูปแบบการออกแบบสะพาน สนใจมาก
Jian Huang Huang

1
นี่เป็นเพียงการปรับปรุง ความตั้งใจของรูปแบบสะพาน: "แยกสิ่งที่เป็นนามธรรมออกจากการปฏิบัติเพื่อให้ทั้งสองสามารถเปลี่ยนแปลงได้อย่างอิสระ" สิ่งที่เป็นนามธรรมและการดำเนินการอยู่ที่นี่?
clapas

จอห์นใส่ไว้ในบล็อกโพสต์ พบว่าเป็นการอ่านที่ดีสำหรับภาพรวมระดับสูง
Vaibhav Bhalla

29

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

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

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

Device drivers เป็นตัวอย่างที่อ้างถึงบ่อยครั้งของ Bridge แต่ผมว่ามันเป็น Bridge ถ้าคุณกำลังกำหนดสเป็กอินเทอร์เฟซสำหรับผู้จำหน่ายอุปกรณ์ แต่มันเป็นอะแดปเตอร์หากคุณกำลังใช้ไดรเวอร์อุปกรณ์ที่มีอยู่แล้ว จัดเตรียมอินเตอร์เฟสแบบรวม

รหัสฉลาดทั้งสองรูปแบบจะคล้ายกันมาก ธุรกิจที่ชาญฉลาดพวกเขาแตกต่างกัน

ดูเพิ่มเติมที่http://c2.com/cgi/wiki?BridgePattern


เฮ้บิล ฉันไม่เข้าใจว่าทำไมเราจำเป็นต้องใช้รูปแบบบริดจ์ในไดรเวอร์อุปกรณ์ ฉันหมายความว่าเราสามารถมอบหมายการใช้งาน (อ่านเขียนค้นหา ฯลฯ ) ให้กับชั้นเรียนที่ถูกต้องผ่านพหุสัณฐานใช่ไหม? หรือกับผู้เยี่ยมชมอาจจะ? ทำไมต้องเป็น Bridge? ขอบคุณล่วงหน้า.
stdout

1
@zgulser ใช่คุณใช้ polymorphism รูปแบบบริดจ์อธิบายการใช้คลาสย่อยหนึ่งประเภทเพื่อนำไปใช้ในการแยกการปฏิบัติจากนามธรรม
Bill Karwin

คุณหมายถึงการนำ decoupling Shape ไปใช้ (เช่นสี่เหลี่ยม) จากวันที่เป็นสีนามธรรมใช่ไหม? และฉันเชื่อว่าคุณกำลังบอกว่ามีหลายวิธีที่จะทำได้และ Bridge เป็นเพียงหนึ่งในนั้น
stdout

ใช่คลาสย่อยมีประโยชน์อื่น ๆ วิธีเฉพาะในการใช้คลาสย่อยนี้คือสิ่งที่ทำให้รูปแบบบริดจ์
Bill Karwin

และการแยก decoupling ที่ฉันหมายถึงนั้นมาจากอินเตอร์เฟสรูปร่างนามธรรมไปสู่การใช้สี่เหลี่ยมผืนผ้าที่เป็นรูปธรรม ดังนั้นคุณสามารถเขียนโค้ดที่ต้องการวัตถุประเภท "รูปร่าง" ได้แม้ว่าวัตถุคอนกรีตจะเป็นคลาสย่อยของรูปร่างก็ตาม
Bill Karwin

27

จากประสบการณ์ของผมสะพานเป็นรูปแบบที่เกิดขึ้นค่อนข้างบ่อยเพราะมันเป็นวิธีการแก้ปัญหาเมื่อใดก็ตามที่มีสองมิติฉากในโดเมน เช่นรูปร่างและวิธีการวาด, พฤติกรรมและแพลตฟอร์ม, รูปแบบไฟล์และซีเรียลไลเซอร์เป็นต้น

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


22

จุดประสงค์ของBridgeและAdaptorนั้นแตกต่างกันและเราต้องการทั้งสองรูปแบบแยกจากกัน

รูปแบบสะพาน:

  1. มันเป็นรูปแบบโครงสร้าง
  2. สิ่งที่เป็นนามธรรมและการใช้งานจะไม่ผูกพันในเวลารวบรวม
  3. สิ่งที่เป็นนามธรรมและการนำไปใช้งาน - ทั้งสองอย่างสามารถเปลี่ยนแปลงได้โดยไม่มีผลกระทบต่อลูกค้า
  4. ใช้องค์ประกอบมากกว่าการสืบทอด

ใช้รูปแบบบริดจ์เมื่อ:

  1. คุณต้องการรวมเวลาทำงานของการใช้งาน
  2. คุณมีการแพร่กระจายของคลาสที่เกิดจากอินเทอร์เฟซคู่และการใช้งานจำนวนมาก
  3. คุณต้องการแบ่งปันการใช้งานระหว่างวัตถุหลาย ๆ
  4. คุณต้องแมปลำดับชั้นคลาสมุมฉาก

คำตอบ @ John Sonmez แสดงให้เห็นอย่างชัดเจนถึงประสิทธิภาพของรูปแบบสะพานในการลดลำดับชั้นของชั้นเรียน

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

รูปแบบของอะแดปเตอร์ :

  1. มันช่วยให้สองอินเตอร์เฟซที่ไม่เกี่ยวข้องกับการทำงานร่วมกันผ่านวัตถุที่แตกต่างกันอาจจะเล่นบทบาทเดียวกัน
  2. มันปรับเปลี่ยนอินเตอร์เฟซเดิม

ความแตกต่างที่สำคัญ:

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

คำถาม SE ที่เกี่ยวข้องกับแผนภาพ UML และรหัสการทำงาน:

ความแตกต่างระหว่างรูปแบบบริดจ์และรูปแบบของการ์ดเชื่อมต่อ

บทความที่มีประโยชน์:

บทความรูปแบบบริดจ์ซอร์สโค้ด

บทความรูปแบบของอะแดปเตอร์ sourcemaking

บทความรูปแบบสะพาน journaldev

แก้ไข:

ตัวอย่างบริดจ์แบบโลกแห่งความจริง (ตามข้อเสนอแนะ meta.stackoverflow.com ตัวอย่างเว็บไซต์เอกสารที่รวมอยู่ในโพสต์นี้เนื่องจากเอกสารกำลังจะไปถึงดวงอาทิตย์)

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

รูปแบบสะพาน UML จาก Wikipedia:

รูปแบบบริดจ์ UML จาก Wikipedia

คุณมีสี่องค์ประกอบในรูปแบบนี้

Abstraction: มันกำหนดอินเทอร์เฟซ

RefinedAbstraction: มันใช้สิ่งที่เป็นนามธรรม:

Implementor: มันกำหนดอินเทอร์เฟซสำหรับการใช้งาน

ConcreteImplementor: ใช้ส่วนต่อประสาน Implementor

The crux of Bridge pattern :ลำดับชั้นคลาสสองมุมฉากใช้องค์ประกอบ (และไม่มีการสืบทอด) ลำดับชั้นของนามธรรมและลำดับชั้นการนำไปปฏิบัติสามารถแตกต่างกันอย่างอิสระ การดำเนินการไม่เคยหมายถึงสิ่งที่เป็นนามธรรม สิ่งที่เป็นนามธรรมประกอบด้วยส่วนต่อประสานการนำไปใช้งานในฐานะสมาชิก (ผ่านองค์ประกอบ) องค์ประกอบนี้จะลดลำดับชั้นการสืบทอดอีกระดับหนึ่ง

กรณีการใช้คำจริง:

เปิดใช้งานยานพาหนะต่าง ๆ เพื่อให้มีทั้งระบบเกียร์ธรรมดาและเกียร์อัตโนมัติ

รหัสตัวอย่าง:

/* Implementor interface*/
interface Gear{
    void handleGear();
}

/* Concrete Implementor - 1 */
class ManualGear implements Gear{
    public void handleGear(){
        System.out.println("Manual gear");
    }
}
/* Concrete Implementor - 2 */
class AutoGear implements Gear{
    public void handleGear(){
        System.out.println("Auto gear");
    }
}
/* Abstraction (abstract class) */
abstract class Vehicle {
    Gear gear;
    public Vehicle(Gear gear){
        this.gear = gear;
    }
    abstract void addGear();
}
/* RefinedAbstraction - 1*/
class Car extends Vehicle{
    public Car(Gear gear){
        super(gear);
        // initialize various other Car components to make the car
    }
    public void addGear(){
        System.out.print("Car handles ");
        gear.handleGear();
    }
}
/* RefinedAbstraction - 2 */
class Truck extends Vehicle{
    public Truck(Gear gear){
        super(gear);
        // initialize various other Truck components to make the car
    }
    public void addGear(){
        System.out.print("Truck handles " );
        gear.handleGear();
    }
}
/* Client program */
public class BridgeDemo {    
    public static void main(String args[]){
        Gear gear = new ManualGear();
        Vehicle vehicle = new Car(gear);
        vehicle.addGear();

        gear = new AutoGear();
        vehicle = new Car(gear);
        vehicle.addGear();

        gear = new ManualGear();
        vehicle = new Truck(gear);
        vehicle.addGear();

        gear = new AutoGear();
        vehicle = new Truck(gear);
        vehicle.addGear();
    }
}

เอาท์พุท:

Car handles Manual gear
Car handles Auto gear
Truck handles Manual gear
Truck handles Auto gear

คำอธิบาย:

  1. Vehicle เป็นสิ่งที่เป็นนามธรรม
  2. CarและTruckการใช้งานที่เป็นรูปธรรมสองประการVehicleคือ
  3. VehicleaddGear()กำหนดวิธีนามธรรม:
  4. Gear เป็นอินเตอร์เฟสของ implementor
  5. ManualGearและAutoGearมีการใช้งานสองอย่างของ Gear
  6. Vehicleมีimplementorส่วนต่อประสานแทนที่จะใช้ส่วนต่อประสาน Compositonอินเทอร์เฟซของ implementor คือปมของรูปแบบนี้: มันช่วยให้นามธรรมและการใช้งานแตกต่างกันไปอย่างอิสระ
  7. CarและTruckกำหนดการใช้งาน (Abstraction ที่นิยามใหม่) สำหรับ Abstraction: addGear()ประกอบด้วย Gear- Either ManualหรือAuto

ใช้กรณีสำหรับรูปแบบบริดจ์ :

  1. สิ่งที่เป็นนามธรรมและการใช้งานสามารถเปลี่ยนแปลงซึ่งกันและกันและพวกเขาจะไม่ผูกพันในเวลารวบรวม
  2. แผนผังลำดับชั้นมุมฉาก - หนึ่งสำหรับAbstractionและอีกหนึ่งสำหรับการนำไปใช้

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

แม้ว่าเกียร์ธรรมดาและเกียร์อัตโนมัติอาจต้องการการปรับแต่งที่แตกต่างกันสำหรับรถบรรทุกและรถยนต์
andigor

9

ฉันใช้รูปแบบบริดจ์ในที่ทำงาน ฉันเขียนโปรแกรมใน C ++ ซึ่งมักเรียกว่า PIMPL idiom (ตัวชี้ไปยังการนำไปใช้) ดูเหมือนว่านี้:

class A
{
public: 
  void foo()
  {
    pImpl->foo();
  }
private:
  Aimpl *pImpl;
};

class Aimpl
{
public:
  void foo();
  void bar();
};  

ในตัวอย่างclass Aนี้มีอินเตอร์เฟสและclass Aimplมีการนำไปใช้งาน

สิ่งหนึ่งที่ใช้สำหรับรูปแบบนี้คือการเปิดเผยเพียงบางส่วนของสมาชิกสาธารณะของชั้นเรียนการใช้งาน แต่ไม่อื่น ๆ ในตัวอย่างAimpl::foo()สามารถเรียกผ่านส่วนต่อประสานสาธารณะAได้ แต่ไม่ใช่Aimpl::bar()

ประโยชน์อีกประการหนึ่งคือการที่คุณสามารถกำหนดในส่วนหัวของแฟ้มที่แยกต่างหากที่ไม่จำเป็นต้องรวมโดยผู้ใช้ของAimpl Aสิ่งที่คุณต้องทำคือใช้การประกาศล่วงหน้าAimplก่อนAกำหนดและย้ายนิยามของฟังก์ชันสมาชิกทั้งหมดที่อ้างอิงpImplไปยังไฟล์. cpp สิ่งนี้ให้ความสามารถในการรักษาAimplส่วนหัวและลดเวลาในการคอมไพล์


2
หากคุณใช้รูปแบบนี้ AImpl ก็ไม่จำเป็นต้องมีส่วนหัว ฉันเพิ่งจะใส่มันไว้ในไฟล์การใช้งานสำหรับคลาส A
1800 ข้อมูล

ผู้ดำเนินการของคุณเป็นแบบส่วนตัว ฉันมีคำถามใหม่เกี่ยวกับเรื่องนี้ดูstackoverflow.com/questions/17680762/…
Roland

7

ในการใส่ตัวอย่างรูปร่างในรหัส:

#include<iostream>
#include<string>
#include<cstdlib>

using namespace std;

class IColor
{
public:
    virtual string Color() = 0;
};

class RedColor: public IColor
{
public:
    string Color()
    {
        return "of Red Color";
    }
};

class BlueColor: public IColor
{
public:
    string Color()
    {
        return "of Blue Color";
    }
};


class IShape
{
public:
virtual string Draw() = 0;
};

class Circle: public IShape
{
        IColor* impl;
    public:
        Circle(IColor *obj):impl(obj){}
        string Draw()
        {
            return "Drawn a Circle "+ impl->Color();
        }
};

class Square: public IShape
{
        IColor* impl;
    public:
        Square(IColor *obj):impl(obj){}
        string Draw()
        {
        return "Drawn a Square "+ impl->Color();;
        }
};

int main()
{
IColor* red = new RedColor();
IColor* blue = new BlueColor();

IShape* sq = new Square(red);
IShape* cr = new Circle(blue);

cout<<"\n"<<sq->Draw();
cout<<"\n"<<cr->Draw();

delete red;
delete blue;
return 1;
}

ผลลัพธ์คือ:

Drawn a Square of Red Color
Drawn a Circle of Blue Color

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


0

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


0

คุณกำลังทำงานให้กับ บริษัท ประกันภัยที่คุณพัฒนาแอปพลิเคชันเวิร์กโฟลว์ที่จัดการงานประเภทต่างๆ: การบัญชีสัญญาการเรียกร้อง นี่คือสิ่งที่เป็นนามธรรม ในด้านการใช้งานคุณจะต้องสามารถสร้างงานจากแหล่งต่าง ๆ ได้เช่นอีเมล, แฟกซ์, อีเมล

คุณเริ่มต้นการออกแบบด้วยคลาสเหล่านี้:

public class Task {...}
public class AccountingTask : Task {...}
public class ContractTask : Task {...}
public class ClaimTask : Task {...}

ตอนนี้เนื่องจากต้องจัดการแต่ละแหล่งข้อมูลด้วยวิธีเฉพาะคุณตัดสินใจที่จะชำนาญแต่ละประเภทงาน:

public class EmailAccountingTask : AccountingTask {...}
public class FaxAccountingTask : AccountingTask {...}
public class EmessagingAccountingTask : AccountingTask {...}

public class EmailContractTask : ContractTask {...}
public class FaxContractTask : ContractTask {...}
public class EmessagingContractTask : ContractTask {...}

public class EmailClaimTask : ClaimTask {...}
public class FaxClaimTask : ClaimTask {...}
public class EmessagingClaimTask : ClaimTask {...}

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

// Source
public class Source {
   public string GetSender();
   public string GetMessage();
   public string GetContractReference();
   (...)
}

public class EmailSource : Source {...}
public class FaxSource : Source {...}
public class EmessagingSource : Source {...}

// Task
public class Task {
   public Task(Source source);
   (...)
}
public class AccountingTask : Task {...}
public class ContractTask : Task {...}
public class ClaimTask : Task {...}

การเพิ่มประเภทงานหรือแหล่งที่มานั้นง่ายขึ้นมาก

หมายเหตุ: นักพัฒนาส่วนใหญ่จะไม่สร้างลำดับชั้นของลำดับชั้น 13 ชั้นเพื่อจัดการปัญหานี้ อย่างไรก็ตามในชีวิตจริงคุณอาจไม่ทราบจำนวนแหล่งที่มาและประเภทของงานล่วงหน้า หากคุณมีเพียงหนึ่งงานและสองประเภทงานคุณอาจไม่แยกงานจากแหล่งที่มา จากนั้นความซับซ้อนโดยรวมจะเพิ่มขึ้นเมื่อมีการเพิ่มแหล่งที่มาและประเภทงานใหม่ เมื่อถึงจุดหนึ่งคุณจะได้รับการปรับโครงสร้างและส่วนใหญ่มักจะจบลงด้วยการแก้ปัญหาสะพาน


-5
Bridge design pattern we can easily understand helping of service and dao layer.

Dao layer -> create common interface for dao layer ->
public interface Dao<T>{
void save(T t);
}
public class AccountDao<Account> implement Dao<Account>{
public void save(Account){
}
}
public LoginDao<Login> implement Dao<Login>{
public void save(Login){
}
}
Service Layer ->
1) interface
public interface BasicService<T>{
    void save(T t);
}
concrete  implementation of service -
Account service -
public class AccountService<Account> implement BasicService<Account>{
 private Dao<Account> accountDao;
 public AccountService(AccountDao dao){
   this.accountDao=dao;
   }
public void save(Account){
   accountDao.save(Account);
 }
}
login service- 
public class LoginService<Login> implement BasicService<Login>{
 private Dao<Login> loginDao;
 public AccountService(LoginDao dao){
   this.loginDao=dao;
   }
public void save(Login){
   loginDao.save(login);
 }
}

public class BridgePattenDemo{
public static void main(String[] str){
BasicService<Account> aService=new AccountService(new AccountDao<Account>());
Account ac=new Account();
aService.save(ac);
}
}
}

5
ฉันรู้สึกแย่เพราะฉันรู้สึกว่านี่เป็นคำตอบที่ซับซ้อนและมีรูปแบบไม่ดี
Zimano

1
เห็นด้วยอย่างสมบูรณ์ว่าคุณจะโพสต์คำตอบในเว็บไซต์นี้ได้อย่างไรโดยไม่ต้องสนใจการเยื้องรหัสและความชัดเจนน้อยที่สุด
Massimiliano Kraus
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.