橋接模式
在軟體系統中,某些型別由於自身的邏輯,它具有兩個或多個維度的變化,那麼如何應對這種“多維度的變化”?這就要使用橋接模式
概述
在軟體系統中,某些型別由於自身的邏輯,它具有兩個或多個維度的變化,那麼如何應對這種“多維度的變化”?如何利用面嚮物件的技術來使得該型別能夠輕鬆的沿著多個方向進行變化,而又不引入額外的複雜度?這就要使用Bridge模式。
意圖
【GOF95】在提出橋樑模式的時候指出,橋樑模式的用意是"將抽象化(Abstraction)與實現化(Implementation)脫耦,使得二者可以獨立地變化"。這句話有三個關鍵詞,也就是抽象化、實現化和脫耦。
抽象化
存在於多個實體中的共同的概念性聯絡,就是抽象化。作為一個過程,抽象化就是忽略一些資訊,從而把不同的實體當做同樣的實體對待【LISKOV94】。
實現化
抽象化給出的具體實現,就是實現化。
脫耦
所謂耦合,就是兩個實體的行為的某種強關聯。而將它們的強關聯去掉,就是耦合的解脫,或稱脫耦。在這裡,脫耦是指將抽象化和實現化之間的耦合解脫開,或者說是將它們之間的強關聯改換成弱關聯。
將兩個角色之間的繼承關係改為聚合關係,就是將它們之間的強關聯改換成為弱關聯。因此,橋樑模式中的所謂脫耦,就是指在一個軟體系統的抽象化和實現化之間使用組合/聚合關係而不是繼承關係,從而使兩者可以相對獨立地變化。這就是橋樑模式的用意。
結構
可以看出,這個系統含有兩個等級結構,也就是:
由抽象化角色和修正抽象化角色組成的抽象化等級結構。
由實現化角色和兩個具體實現化角色所組成的實現化等級結構。
橋樑模式所涉及的角色有:
抽象化(Abstraction)角色:抽象化給出的定義,並儲存一個對實現化物件的引用。
修正抽象化(Refined Abstraction)角色:擴充套件抽象化角色,改變和修正父類對抽象化的定義。
實現化(Implementor)角色:這個角色給出實現化角色的介面,但不給出具體的實現。必須指出的是,這個介面不一定和抽象化角色的介面定義相同,實際上,這兩個介面可以非常不一樣。實現化角色應當只給出底層操作,而抽象化角色應當只給出基於底層操作的更高一層的操作。
具體實現化(Concrete Implementor)角色:這個角色給出實現化角色介面的具體實現。
示意性原始碼
// Bridge pattern -- Structural example
using System;
//"Abstraction"
class Abstraction
{
// Fields
protectedImplementor implementor;
// Properties
public Implementor Implementor
set{ implementor = value; }
}
// Methods
virtual public void Operation()
implementor.Operation();
//"Implementor"
abstract class Implementor
abstract public void Operation();
//"RefinedAbstraction"
class RefinedAbstraction : Abstraction
override public void Operation()
//"ConcreteImplementorA"
class ConcreteImplementorA : Implementor
Console.WriteLine("ConcreteImplementorA Operation");
//"ConcreteImplementorB"
class ConcreteImplementorB : Implementor
Console.WriteLine("ConcreteImplementorB Operation");
///
/// Client test
public class Client
public static void Main( string[] args )
Abstraction abstraction = new RefinedAbstraction();
// Set implementation and call
abstraction.Implementor = new ConcreteImplementorA();
abstraction.Operation();
// Change implemention and call
abstraction.Implementor = new ConcreteImplementorB();
C++橋接模式
由遇到的問題引出橋接模式
總結面向物件實際上就兩句話:一是松耦合(Coupling),二是高內聚(Cohesion)。面向物件系統追求的目標就是儘可能地提高系統模組內部的內聚(Cohesion)、儘可能降低模組間的耦合(Coupling)。然而這也是面向物件設計過程中最為難把握的部分,大家肯定在OO 系統的開發過程中遇到這樣的問題:
客戶給了你一個需求,於是使用一個類來實現(A);
客戶需求變化,有兩個演算法實現功能,於是改變設計,我們透過一個抽象的基類,再定義兩個具體類實現兩個不同的演算法(A1 和 A2);
客戶又告訴我們說對於不同的作業系統,於是再抽象一個層次,作為一個抽象基類A0,在分別為每個作業系統派生具體類(A00 和 A01,其中 A00 表示原來的類 A)實現不同作業系統上的客戶需求,這樣我們就有了一共 4 個類。
可能使用者的需求又有變化,比如說又有了一種新的演算法……..
我們陷入了一個需求變化的鬱悶當中,也因此帶來了類的迅速膨脹。
橋接模式則正是解決了這類問題。
模式選擇
橋接模式典型的結構圖為:
圖 2-1:橋接模式結構圖
在橋接模式的結構圖中可以看到,系統被分為兩個相對獨立的部分,左邊是抽象部分,右邊是實現部分,這兩個部分可以互相獨立地進行修改:例如上面問題中的客戶需求變化,當用戶需求需要從 Abstraction 派生一個具體子類時候,並不需要像上面透過繼承方式實現時候需要新增子類 A1 和 A2 了。另外當上面問題中由於演算法新增也只用改變右邊實現(新增一個具體化子類),而右邊不用在變化,也不用新增具體子類了。
一切都變得 elegant!
橋接模式
在軟體系統中,某些型別由於自身的邏輯,它具有兩個或多個維度的變化,那麼如何應對這種“多維度的變化”?這就要使用橋接模式
概述
在軟體系統中,某些型別由於自身的邏輯,它具有兩個或多個維度的變化,那麼如何應對這種“多維度的變化”?如何利用面嚮物件的技術來使得該型別能夠輕鬆的沿著多個方向進行變化,而又不引入額外的複雜度?這就要使用Bridge模式。
意圖
【GOF95】在提出橋樑模式的時候指出,橋樑模式的用意是"將抽象化(Abstraction)與實現化(Implementation)脫耦,使得二者可以獨立地變化"。這句話有三個關鍵詞,也就是抽象化、實現化和脫耦。
抽象化
存在於多個實體中的共同的概念性聯絡,就是抽象化。作為一個過程,抽象化就是忽略一些資訊,從而把不同的實體當做同樣的實體對待【LISKOV94】。
實現化
抽象化給出的具體實現,就是實現化。
脫耦
所謂耦合,就是兩個實體的行為的某種強關聯。而將它們的強關聯去掉,就是耦合的解脫,或稱脫耦。在這裡,脫耦是指將抽象化和實現化之間的耦合解脫開,或者說是將它們之間的強關聯改換成弱關聯。
將兩個角色之間的繼承關係改為聚合關係,就是將它們之間的強關聯改換成為弱關聯。因此,橋樑模式中的所謂脫耦,就是指在一個軟體系統的抽象化和實現化之間使用組合/聚合關係而不是繼承關係,從而使兩者可以相對獨立地變化。這就是橋樑模式的用意。
結構
可以看出,這個系統含有兩個等級結構,也就是:
由抽象化角色和修正抽象化角色組成的抽象化等級結構。
由實現化角色和兩個具體實現化角色所組成的實現化等級結構。
橋樑模式所涉及的角色有:
抽象化(Abstraction)角色:抽象化給出的定義,並儲存一個對實現化物件的引用。
修正抽象化(Refined Abstraction)角色:擴充套件抽象化角色,改變和修正父類對抽象化的定義。
實現化(Implementor)角色:這個角色給出實現化角色的介面,但不給出具體的實現。必須指出的是,這個介面不一定和抽象化角色的介面定義相同,實際上,這兩個介面可以非常不一樣。實現化角色應當只給出底層操作,而抽象化角色應當只給出基於底層操作的更高一層的操作。
具體實現化(Concrete Implementor)角色:這個角色給出實現化角色介面的具體實現。
示意性原始碼
// Bridge pattern -- Structural example
using System;
//"Abstraction"
class Abstraction
{
// Fields
protectedImplementor implementor;
// Properties
public Implementor Implementor
{
set{ implementor = value; }
}
// Methods
virtual public void Operation()
{
implementor.Operation();
}
}
//"Implementor"
abstract class Implementor
{
// Methods
abstract public void Operation();
}
//"RefinedAbstraction"
class RefinedAbstraction : Abstraction
{
// Methods
override public void Operation()
{
implementor.Operation();
}
}
//"ConcreteImplementorA"
class ConcreteImplementorA : Implementor
{
// Methods
override public void Operation()
{
Console.WriteLine("ConcreteImplementorA Operation");
}
}
//"ConcreteImplementorB"
class ConcreteImplementorB : Implementor
{
// Methods
override public void Operation()
{
Console.WriteLine("ConcreteImplementorB Operation");
}
}
///
/// Client test
///
public class Client
{
public static void Main( string[] args )
{
Abstraction abstraction = new RefinedAbstraction();
// Set implementation and call
abstraction.Implementor = new ConcreteImplementorA();
abstraction.Operation();
// Change implemention and call
abstraction.Implementor = new ConcreteImplementorB();
abstraction.Operation();
}
}
C++橋接模式
由遇到的問題引出橋接模式
總結面向物件實際上就兩句話:一是松耦合(Coupling),二是高內聚(Cohesion)。面向物件系統追求的目標就是儘可能地提高系統模組內部的內聚(Cohesion)、儘可能降低模組間的耦合(Coupling)。然而這也是面向物件設計過程中最為難把握的部分,大家肯定在OO 系統的開發過程中遇到這樣的問題:
客戶給了你一個需求,於是使用一個類來實現(A);
客戶需求變化,有兩個演算法實現功能,於是改變設計,我們透過一個抽象的基類,再定義兩個具體類實現兩個不同的演算法(A1 和 A2);
客戶又告訴我們說對於不同的作業系統,於是再抽象一個層次,作為一個抽象基類A0,在分別為每個作業系統派生具體類(A00 和 A01,其中 A00 表示原來的類 A)實現不同作業系統上的客戶需求,這樣我們就有了一共 4 個類。
可能使用者的需求又有變化,比如說又有了一種新的演算法……..
我們陷入了一個需求變化的鬱悶當中,也因此帶來了類的迅速膨脹。
橋接模式則正是解決了這類問題。
模式選擇
橋接模式典型的結構圖為:
圖 2-1:橋接模式結構圖
在橋接模式的結構圖中可以看到,系統被分為兩個相對獨立的部分,左邊是抽象部分,右邊是實現部分,這兩個部分可以互相獨立地進行修改:例如上面問題中的客戶需求變化,當用戶需求需要從 Abstraction 派生一個具體子類時候,並不需要像上面透過繼承方式實現時候需要新增子類 A1 和 A2 了。另外當上面問題中由於演算法新增也只用改變右邊實現(新增一個具體化子類),而右邊不用在變化,也不用新增具體子類了。
一切都變得 elegant!