Kapan Anda menggunakan Pola Jembatan? Apa bedanya dengan pola Adaptor?


154

Adakah yang pernah menggunakan Pola Jembatan dalam aplikasi dunia nyata? Jika demikian, bagaimana Anda menggunakannya? Apakah ini saya, atau hanya Pola Adaptor dengan sedikit ketergantungan injeksi yang dimasukkan ke dalam campuran? Apakah itu benar-benar pantas mendapatkan polanya sendiri?


Harap pertimbangkan untuk menerima jawaban berbeda untuk pertanyaan ini. Jawaban yang diterima saat ini salah dan tidak membantu. Jawaban yang lebih baru jauh lebih unggul.
jaco0646

The book GOF menjawab pertanyaan ini secara langsung.
jaco0646

Jawaban:


76

Contoh klasik dari pola Bridge digunakan dalam definisi bentuk di lingkungan UI (lihat entri Wikipedia pola jembatan ). Pola Bridge adalah gabungan dari pola Template dan Strategi .

Ini adalah pandangan umum beberapa aspek dari pola Adaptor dalam pola Bridge. Namun, mengutip dari artikel ini :

Pada pandangan pertama, pola Bridge sangat mirip dengan pola Adaptor di mana kelas digunakan untuk mengkonversi satu jenis antarmuka ke yang lain. Namun, maksud dari pola Adaptor adalah untuk membuat satu atau lebih antarmuka kelas terlihat sama dengan kelas tertentu. Pola Bridge dirancang untuk memisahkan antarmuka kelas dari implementasinya sehingga Anda dapat memvariasikan atau mengganti implementasi tanpa mengubah kode klien.


1
Bridge tidak ada hubungannya dengan Template atau Strategi. Jembatan adalah pola struktural. Template dan Strategi adalah pola perilaku.
jaco0646

249

Ada kombinasi jawaban Federico dan John .

Kapan:

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

Refactor ke:

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

6
Mengapa Anda melakukan pewarisan untuk warna?
vainolo

10
@Vainolo karena Warna adalah antarmuka dan Biru, Merah adalah warna beton
Weltschmerz

3
Ini hanya refactoring. Maksud pola jembatan: "Putuskan abstraksi dari implementasinya sehingga keduanya dapat berbeda secara independen." Di mana abstraksi dan di mana implementasinya di sini?
clapas

1
Bukankah Rectangle (Warna) lebih abstrak dari pada BlueRectangle?
Anton Shchastnyi

2
@clapas, Abstraction adalah "Shape.color" properti, oleh karena itu kelas Merah dan kelas Biru adalah implementasi, dan antarmuka Warna adalah jembatan.
reco

230

Pola Bridge adalah aplikasi dari saran lama, "lebih suka komposisi daripada warisan". Ini menjadi berguna ketika Anda harus mensubklasifikasikan waktu yang berbeda dengan cara yang ortogonal satu sama lain. Katakanlah Anda harus menerapkan hierarki bentuk berwarna. Anda tidak akan membentuk subclass Shape dengan Rectangle dan Circle dan kemudian subclass Rectangle dengan RedRectangle, BlueRectangle dan GreenRectangle dan sama untuk Circle, bukan? Anda lebih suka mengatakan bahwa setiap Bentuk memiliki Warna dan menerapkan hierarki warna, dan itu adalah Pola Jembatan. Yah, saya tidak akan menerapkan "hierarki warna", tetapi Anda mendapatkan ide ...


1
Lihat juga diagram Anton Shchastnyi di bawah ini untuk ilustrasi grafis dari penjelasan ini.
NomadeNumerique

2
Saya tidak berpikir warna adalah contoh yang baik untuk hierarki implementasi, itu agak membingungkan. Ada contoh yang baik dari pola Bridge dalam "Pola desain" oleh GoF, di mana implementasi bergantung pada platform: PM IBM, UNIX's X dll.
clapas

215

Kapan:

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

Refactor ke:

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

3
Saya pikir ini pendekatan yang sangat pragmatis untuk pola: 1) menjelaskan desain lurus ke depan yang kurang optimal 2) desain / kode refactor untuk faktor yang lebih baik
Alexey

1
Gunakan konsep matematika untuk menjelaskan pola desain Jembatan. Sangat tertarik.
Jian Huang

1
Ini hanya refactoring. Maksud pola jembatan: "Putuskan abstraksi dari implementasinya sehingga keduanya dapat berbeda secara independen." Di mana abstraksi dan di mana implementasinya di sini?
clapas

John menempatkannya dengan baik di posting blog . Menemukannya sebagai bacaan yang bagus untuk ikhtisar tingkat tinggi.
Vaibhav Bhalla

29

Adaptor dan Jembatan tentu terkait, dan perbedaannya halus. Ada kemungkinan bahwa beberapa orang yang berpikir mereka menggunakan salah satu pola ini sebenarnya menggunakan pola yang lain.

Penjelasan yang saya lihat adalah Adaptor digunakan ketika Anda mencoba menyatukan antarmuka beberapa kelas yang tidak kompatibel yang sudah ada . Adaptor berfungsi sebagai semacam penerjemah untuk implementasi yang dapat dianggap sebagai warisan .

Sedangkan pola Bridge digunakan untuk kode yang lebih cenderung menjadi greenfield. Anda sedang merancang Jembatan untuk menyediakan antarmuka abstrak untuk implementasi yang perlu beragam, tetapi Anda juga mendefinisikan antarmuka kelas implementasi tersebut.

Driver perangkat adalah contoh yang sering dikutip dari Bridge, tapi saya akan mengatakan itu Bridge jika Anda mendefinisikan spesifikasi antarmuka untuk vendor perangkat, tetapi itu adalah Adaptor jika Anda mengambil driver perangkat yang ada dan membuat kelas wrapper untuk menyediakan antarmuka terpadu.

Jadi kode-bijaksana, kedua pola ini sangat mirip. Dari segi bisnis, mereka berbeda.

Lihat juga http://c2.com/cgi/wiki?BridgePattern


Hai Bill. Saya tidak mengerti mengapa kita perlu menggunakan pola Bridge pada driver perangkat. Maksud saya, kita dapat dengan mudah mendelegasikan implementasi (membaca, menulis, mencari dll.) Ke kelas yang benar melalui polimorfisme bukan? Atau dengan Pengunjung mungkin? Kenapa harus jembatan? Terima kasih sebelumnya.
stdout

1
@ zgulser, ya, Anda memang menggunakan polimorfisme. Pola Bridge menjelaskan satu jenis penggunaan subclass untuk memisahkan implementasi dari abstraksi.
Bill Karwin

Anda berarti implementasi Shape decoupling (mis. Rectangle) dari mari hari Warna abstraksi bukan? Dan saya yakin Anda mengatakan ada banyak cara untuk melakukannya dan Bridge hanyalah salah satunya.
stdout

Ya, subclassing memiliki kegunaan lain. Cara khusus menggunakan subclass inilah yang membuatnya menjadi pola Bridge.
Bill Karwin

Dan decoupling yang saya maksudkan adalah dari antarmuka Shape abstrak ke implementasi Rectangle konkret. Jadi, Anda dapat menulis kode yang membutuhkan objek tipe "Shape", meskipun objek konkretnya benar-benar adalah beberapa subkelas Shape.
Bill Karwin

27

Dalam pengalaman saya, Bridge adalah pola yang cukup sering berulang, karena itu solusi setiap kali ada dua dimensi ortogonal dalam domain . Misalnya bentuk dan metode menggambar, perilaku dan platform, format file dan serializers dan sebagainya.

Dan sebuah saran: selalu pikirkan pola desain dari perspektif konseptual , bukan dari perspektif implementasi. Dari sudut pandang yang benar, Bridge tidak dapat disamakan dengan Adaptor, karena mereka menyelesaikan masalah yang berbeda, dan komposisi lebih unggul daripada warisan bukan karena kepentingan itu sendiri, tetapi karena memungkinkan untuk menangani masalah ortogonal secara terpisah.


22

Maksud dari Bridge dan Adaptor berbeda dan kita membutuhkan kedua pola secara terpisah.

Pola jembatan:

  1. Ini adalah pola struktural
  2. Abstraksi dan implementasi tidak terikat pada waktu kompilasi
  3. Abstraksi dan implementasi - keduanya dapat bervariasi tanpa dampak pada klien
  4. Menggunakan komposisi melebihi pewarisan.

Gunakan pola Jembatan saat:

  1. Anda ingin mengikat waktu pelaksanaan,
  2. Anda memiliki proliferasi kelas yang dihasilkan dari antarmuka yang digabungkan dan banyak implementasi,
  3. Anda ingin berbagi implementasi di antara banyak objek,
  4. Anda perlu memetakan hierarki kelas ortogonal.

@ John Sonmez menjawab dengan jelas menunjukkan efektivitas pola jembatan dalam mengurangi hirarki kelas.

Anda dapat merujuk ke tautan dokumentasi di bawah ini untuk mendapatkan wawasan yang lebih baik tentang pola jembatan dengan contoh kode

Pola adaptor :

  1. Ini memungkinkan dua antarmuka yang tidak berhubungan untuk bekerja bersama melalui objek yang berbeda, mungkin memainkan peran yang sama.
  2. Ini memodifikasi antarmuka asli.

Perbedaan utama:

  1. Adaptor membuat hal-hal berfungsi setelah dirancang; Jembatan membuat mereka bekerja sebelum mereka.
  2. Bridge dirancang di muka untuk membiarkan abstraksi dan implementasinya bervariasi secara independen . Adaptor dipasang untuk membuat kelas yang tidak terkait bekerja bersama.
  3. Maksudnya: Adaptor memungkinkan dua antarmuka yang tidak terkait untuk bekerja bersama. Bridge memungkinkan Abstraksi dan implementasi bervariasi secara independen.

Pertanyaan SE terkait dengan diagram UML dan kode kerja:

Perbedaan antara pola Bridge dan pola Adaptor

Artikel yang berguna:

artikel tentang pola pembuatan jembatan

pembuatan sumber pola artikel adaptor

artikel pola jembatan journaldev

EDIT:

Bridge Pattern contoh dunia nyata (Sesuai saran meta.stackoverflow.com, masukkan contoh situs dokumentasi dalam posting ini karena dokumentasi akan terbenam di matahari)

Pola jembatan memisahkan abstraksi dari implementasi sehingga keduanya dapat bervariasi secara independen. Itu telah dicapai dengan komposisi daripada warisan.

Jembatan pola UML dari Wikipedia:

Jembatan pola UML dari Wikipedia

Anda memiliki empat komponen dalam pola ini.

Abstraction: Ini mendefinisikan sebuah antarmuka

RefinedAbstraction: Ini mengimplementasikan abstraksi:

Implementor: Ini mendefinisikan antarmuka untuk implementasi

ConcreteImplementor: Ini mengimplementasikan antarmuka Implementor.

The crux of Bridge pattern :Dua hierarki kelas ortogonal menggunakan komposisi (dan tidak ada warisan). Hirarki Abstraksi dan Implementasi hierarki dapat bervariasi secara independen. Implementasi tidak pernah merujuk Abstraksi. Abstraksi berisi antarmuka Implementasi sebagai anggota (melalui komposisi). Komposisi ini mengurangi satu tingkat hierarki warisan.

Kasus penggunaan kata asli:

Aktifkan kendaraan yang berbeda untuk memiliki kedua versi sistem manual dan auto gear.

Kode contoh:

/* 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();
    }
}

keluaran:

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

Penjelasan:

  1. Vehicle adalah abstraksi.
  2. Cardan Truckdua implementasi konkret dari Vehicle.
  3. Vehiclemendefinisikan metode abstrak: addGear().
  4. Gear adalah antarmuka implementor
  5. ManualGeardan AutoGeardua implementasi dari Gear
  6. Vehiclemengandung implementorantarmuka daripada mengimplementasikan antarmuka. Compositonantarmuka implementor adalah inti dari pola ini: Memungkinkan abstraksi dan implementasi bervariasi secara independen.
  7. Cardan Truckmendefinisikan implementasi (abstraksi ulang) untuk abstraksi addGear():: Ini berisi Gear- Entah ManualatauAuto

Gunakan case untuk pola Bridge :

  1. Abstraksi dan Implementasi dapat berubah independen satu sama lain dan mereka tidak terikat pada waktu kompilasi
  2. Peta hierarki ortogonal - Satu untuk Abstraksi dan satu untuk Implementasi .

"Adaptor membuat sesuatu berfungsi setelah dirancang, Bridge membuat mereka berfungsi sebelum mereka." Anda mungkin ingin melihat Adaptor Pluggable. Ini adalah variasi dari Adaptor yang dijelaskan oleh GoF di bagian "Adaptor" dari buku Pola Desain mereka. Tujuannya adalah untuk membuat antarmuka untuk kelas yang belum ada. Adaptor pluggable bukan Bridge, jadi saya tidak merasa poin pertama valid.
c1moore

Meskipun gigi manual dan otomatis mungkin memerlukan implementasi yang berbeda untuk truk dan mobil
andigor

9

Saya telah menggunakan pola jembatan di tempat kerja. Saya memprogram dalam C ++, di mana sering disebut idiom PIMPL (pointer ke implementasi). Ini terlihat seperti ini:

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

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

Dalam contoh ini class Aberisi antarmuka, danclass Aimpl berisi implementasinya.

Satu kegunaan untuk pola ini adalah untuk mengekspos hanya beberapa anggota publik dari kelas implementasi, tetapi tidak yang lain. Dalam contoh hanya Aimpl::foo()dapat dipanggil melalui antarmuka publik A, tetapi tidakAimpl::bar()

Keuntungan lain adalah bahwa Anda dapat menentukan Aimpldalam file header terpisah yang tidak perlu dimasukkan oleh pengguna A. Yang harus Anda lakukan adalah menggunakan deklarasi maju Aimplsebelum Adidefinisikan, dan memindahkan definisi dari semua fungsi anggota yang merujuk pImplke file .cpp. Ini memberi Anda kemampuan untuk menjaga Aimpltajuk pribadi, dan mengurangi waktu kompilasi.


2
Jika Anda menggunakan pola ini maka AImpl bahkan tidak perlu header. Saya hanya memasukkannya dalam file implementasi untuk kelas A
1800 INFORMASI

Implementor Anda bersifat pribadi. Saya punya pertanyaan baru dalam hal ini, lihat stackoverflow.com/questions/17680762/...
Roland

7

Untuk memasukkan contoh bentuk dalam kode:

#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;
}

Outputnya adalah:

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

Perhatikan kemudahan dengan warna dan bentuk baru yang dapat ditambahkan ke sistem tanpa menyebabkan ledakan subkelas karena permutasi.


0

bagi saya, saya menganggapnya sebagai mekanisme di mana Anda dapat bertukar antarmuka. Di dunia nyata Anda mungkin memiliki kelas yang dapat menggunakan lebih dari satu antarmuka, Bridge memungkinkan Anda bertukar.


0

Anda bekerja untuk perusahaan asuransi tempat Anda mengembangkan aplikasi alur kerja yang mengelola berbagai jenis tugas: akuntansi, kontrak, klaim. Ini adalah abstraksi. Di sisi implementasi, Anda harus dapat membuat tugas dari berbagai sumber: email, faks, e-messaging.

Anda memulai desain Anda dengan kelas-kelas ini:

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

Sekarang, karena setiap sumber harus ditangani dengan cara tertentu, Anda memutuskan untuk mengkhususkan setiap jenis tugas:

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 {...}

Anda berakhir dengan 13 kelas. Menambahkan jenis tugas atau jenis sumber menjadi menantang. Menggunakan pola jembatan menghasilkan sesuatu yang lebih mudah untuk dipelihara dengan memisahkan tugas (abstraksi) dari sumber (yang merupakan masalah implementasi):

// 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 {...}

Menambahkan jenis tugas atau sumber sekarang jauh lebih mudah.

Catatan: Sebagian besar pengembang tidak akan membuat hierarki 13 kelas di muka untuk menangani masalah ini. Namun, dalam kehidupan nyata, Anda mungkin tidak tahu sebelumnya jumlah sumber dan jenis tugas; jika Anda hanya memiliki satu sumber dan dua jenis tugas, Anda mungkin tidak akan memisahkan tugas dari Sumber. Kemudian, kompleksitas keseluruhan bertambah ketika sumber dan jenis tugas baru ditambahkan. Pada titik tertentu, Anda akan melakukan refactor dan, paling sering, berakhir dengan solusi seperti jembatan.


-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
Saya tidak memilih karena saya merasa ini adalah jawaban yang berbelit-belit dan tidak berformat.
Zimano

1
Sepenuhnya setuju, bagaimana Anda dapat memposting jawaban di situs ini tanpa sedikit perhatian pada lekukan dan kejelasan kode
Massimiliano Kraus
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.