Bridge橋模式是一種“單一職責”模式
- 在軟件組件的設計中,如果責任劃分得不清晰,使用繼承得到的結果往往是隨着需求的變化,子類急劇膨脹,同時充斥者大量重複代碼。這時候的關鍵是劃清責任
動機
- 由於某些類型的固有的實現邏輯,使得它們具有兩個變化的維度,乃至多個維度的變化
- 如何應對這種“多維度的變化”?如何利用面向對象技術來使得類型可以輕鬆沿着兩個乃至多個方向變化,而不引入額外的複雜度?
定義
- 將抽象部分(業務功能)與實現部分(平臺實現)分離,使它們都可以獨立地變化
結構
代碼對比
bridge1.cpp未使用橋模式
class Messager{
public:
virtual void Login(string username, string password)=0;
virtual void SendMessage(string message)=0;
virtual void SendPicture(Image image)=0;
virtual void PlaySound()=0;
virtual void DrawShape()=0;
virtual void WriteText()=0;
virtual void Connect()=0;
virtual ~Messager(){}
};
//平臺實現
class PCMessagerBase : public Messager{
public:
virtual void PlaySound(){
//**********
}
virtual void DrawShape(){
//**********
}
virtual void WriteText(){
//**********
}
virtual void Connect(){
//**********
}
};
class MobileMessagerBase : public Messager{
public:
virtual void PlaySound(){
//==========
}
virtual void DrawShape(){
//==========
}
virtual void WriteText(){
//==========
}
virtual void Connect(){
//==========
}
};
//業務抽象
class PCMessagerLite : public PCMessagerBase {
public:
virtual void Login(string username, string password){
PCMessagerBase::Connect();
//........
}
virtual void SendMessage(string message){
PCMessagerBase::WriteText();
//........
}
virtual void SendPicture(Image image){
PCMessagerBase::DrawShape();
//........
}
};
class PCMessagerPerfect : public PCMessagerBase {
public:
virtual void Login(string username, string password){
PCMessagerBase::PlaySound();
//********
PCMessagerBase::Connect();
//........
}
virtual void SendMessage(string message){
PCMessagerBase::PlaySound();
//********
PCMessagerBase::WriteText();
//........
}
virtual void SendPicture(Image image){
PCMessagerBase::PlaySound();
//********
PCMessagerBase::DrawShape();
//........
}
};
class MobileMessagerLite : public MobileMessagerBase {
public:
virtual void Login(string username, string password){
MobileMessagerBase::Connect();
//........
}
virtual void SendMessage(string message){
MobileMessagerBase::WriteText();
//........
}
virtual void SendPicture(Image image){
MobileMessagerBase::DrawShape();
//........
}
};
class MobileMessagerPerfect : public MobileMessagerBase {
public:
virtual void Login(string username, string password){
MobileMessagerBase::PlaySound();
//********
MobileMessagerBase::Connect();
//........
}
virtual void SendMessage(string message){
MobileMessagerBase::PlaySound();
//********
MobileMessagerBase::WriteText();
//........
}
virtual void SendPicture(Image image){
MobileMessagerBase::PlaySound();
//********
MobileMessagerBase::DrawShape();
//........
}
};
void Process(){
//編譯時裝配
Messager *m =
new MobileMessagerPerfect();
}
bridge2.cpp橋模式
class Messager{
protected:
MessagerImp* messagerImp;//...
public:
virtual void Login(string username, string password)=0;
virtual void SendMessage(string message)=0;
virtual void SendPicture(Image image)=0;
virtual ~Messager(){}
};
class MessagerImp{
public:
virtual void PlaySound()=0;
virtual void DrawShape()=0;
virtual void WriteText()=0;
virtual void Connect()=0;
virtual MessagerImp(){}
};
//平臺實現 n
class PCMessagerImp : public MessagerImp{
public:
virtual void PlaySound(){
//**********
}
virtual void DrawShape(){
//**********
}
virtual void WriteText(){
//**********
}
virtual void Connect(){
//**********
}
};
class MobileMessagerImp : public MessagerImp{
public:
virtual void PlaySound(){
//==========
}
virtual void DrawShape(){
//==========
}
virtual void WriteText(){
//==========
}
virtual void Connect(){
//==========
}
};
//業務抽象 m
//類的數目:1+n+m
class MessagerLite :public Messager {
public:
virtual void Login(string username, string password){
messagerImp->Connect();
//........
}
virtual void SendMessage(string message){
messagerImp->WriteText();
//........
}
virtual void SendPicture(Image image){
messagerImp->DrawShape();
//........
}
};
class MessagerPerfect :public Messager {
public:
virtual void Login(string username, string password){
messagerImp->PlaySound();
//********
messagerImp->Connect();
//........
}
virtual void SendMessage(string message){
messagerImp->PlaySound();
//********
messagerImp->WriteText();
//........
}
virtual void SendPicture(Image image){
messagerImp->PlaySound();
//********
messagerImp->DrawShape();
//........
}
};
void Process(){
//運行時裝配
MessagerImp* mImp=new PCMessagerImp();
Messager *m =new MessagerPerfect(mImp);
}
對比
- bridge1.cpp中
Messager
接口中的方法有平臺實現和業務抽象兩種。這兩種方法的變化方向是不同的(平臺實現是穩定的,因爲它的子類都沒有override基類中的方法;而業務抽象是不斷變化的,需要不斷地override)。它們所導致的多態的實現的變化方向也是截然不同的,不符合單一職責的原則
- bridge2.cpp中將原
Messager
接口中的平臺實現和業務抽象兩個維度進行了分割,將抽象部分(業務功能)和實現部分(平臺實現)進行了分離,得到了Messager
和MessagerImp
兩個接口,其中Messager
類中定義了一個MessagerImp
類型的指針,這樣就可以實現基類指針指向派生類的不同對象。
要點總結
- Bridge模式使用“對象間地組合關係”解耦了抽象和實現之間固有的綁定關係,使得抽象和實現可以沿着它們各自的維度變化。所謂抽象和實現沿着各自維度的變化,即“子類化”它們
- Bridge模式有時候類似於多繼承方案,但是多繼承方案往往違背單一職責原則(即一個類只有一個變化的原因),複用性比較差。Bridge模式是比多繼承方案更好的解決方法
- Bridge模式的應用一般在“兩個非常強的變化維度”,有時一個類也有多於兩個的變化維度,這時可以使用Bridge的擴展模式,使用不同的抽象指針進行指向的處理