本文介紹設計模式中的橋接(Bridge)模式的概念,用法,以及實際應用中怎么樣使用橋接模式進行開發。
Bridge模式的概念
Bridge 模式是構造型的設計模式之一。Bridge模式基于類的最小設計原則,通過使用封裝,聚合以及繼承等行為來讓不同的類承擔不同的責任。它的主要特點是把抽象(abstraction)與行為實現(implementation)分離開來,從而可以保持各部分的獨立性以及應對它們的功能擴展。
Bridge模式的應用場景
面向對象的程序設計(OOP)里有類繼承(子類繼承父類)的概念,如果一個類或接口有多個具體實現子類,如果這些子類具有以下特性:
- 存在相對并列的子類屬性。
- 存在概念上的交叉。
- 可變性。
我們就可以用Bridge模式來對其進行抽象與具體,對相關類進行重構。
為了容易理解,我們舉例說明一下,比如屌絲(DiaoSi),假設有2個子類,男屌絲類(ManDiaoSi)與女屌絲類(WomanDiao),它們有[窮挫矮]這個動作行為,通過不同窮挫矮特征的設置,可以將它們設置為比如為擁有黑木耳男屌絲或(擁有擼管王的女屌絲),和擁有紫木耳男屌絲或(擁有擼神的女屌絲)的各種屌絲。
這樣,不管是黑木耳男屌絲還是紫木耳男屌絲,又或是有擼管王的女屌絲還是有擼神的女屌絲,它們都可以是屌絲類的子類,而且:
- 存在相對并列的子類屬性。屌絲的種類,與屌絲窮挫矮的規格是屌絲的2個并列的屬性,沒有概念上的重復。
- 存在概念上的交叉。不管是男屌絲還是女屌絲,都是窮挫矮,黑窮丑的屌絲。
- 可變性。除了男屌絲,女屌絲之外,可能還有人妖屌絲;除了有黑木耳(擼管王)與紫木耳(擼神)特征的屌絲之外,還可能有紫黑木耳(擼圣)的屌絲等等。
這樣一來,我們怎么來設計屌絲類呢?
方法一
通過繼承設計所有可能存在的子類。可能我們會想到下面的這種繼承關系:
屌絲總類:DiaoSi
屌絲子類 - 按種類分類:ManDiaoSi,WomanDiao
屌絲子類 - 按特征分類:擁有黑木耳男屌絲,擁有擼管王的女屌絲,擁有紫木耳男屌絲,擁有擼神的女屌絲
這樣設置特征這個動作就由各個子類加以實現。
但如果以后需要增加一種人妖屌絲(GuyDiaoSi),以及增加一個特征規格紫黑木耳,需要實現的子類將會有:
擁有黑木耳男屌絲,擁有擼管王的女屌絲,擁有紫木耳男屌絲,擁有擼神的女屌絲 擁有紫黑木耳男屌絲 擁有擼管王的人妖屌絲 擁有紫黑木耳人妖屌絲 擁有紫木耳人妖屌絲
等等。
也就是說,這種設計方法,子類數目將隨幾何級數增長。
而且,擁有黑木耳男屌絲,擁有紫木耳人妖屌絲的特征規格相同,它們的特征設置動作應該是一樣的,但現在把它們分成不同的子類,難以避免執行重復的動作行為。
方法二
分別為男屌絲以及女屌絲實現設置不同特征的方法
屌絲總類:DiaoSi
屌絲子類:ManDiaoSi,WomanDiao
然后在男屌絲類里分別提供黑木耳(擼管王)以及紫木耳(擼神)特征的設置方法:
ManDiaoSi extends DiaoSi
{
public setFeatures黑木耳();
public setFeatures紫木耳();
}
在女屌絲類里也分別提供擼管王以及擼神特征的設置方法:
WomanDiao extends DiaoSi
{
public setFeatures擼管王();
public setFeatures擼神();
}
這種情況,子類的數量是被控制了。但一方面,如果每增加一種特征規格,需要修改所有的屌絲子類;另一方面,即使特征的設置行為一樣,但是不同的屌絲子類卻需要提供完全一樣的方法。
在實際的應用開發中,以上2種方法都會造成遷一發而動全身,而且會存在大量的重復代碼。
Bridge模式可以很好的解決這類問題。
Client
Bridge模式的使用者
Abstraction
抽象類接口(接口或抽象類)
維護對行為實現(Implementor)的引用
Refined Abstraction
Abstraction子類
Implementor
行為實現類接口 (Abstraction接口定義了基于Implementor接口的更高層次的操作)
ConcreteImplementor
Implementor子類
Bridge模式的應用范例
我們來看看怎么應用Bridge模式來設計汽車類。
抽象 - Abstraction類:屌絲類及其子類:
屌絲總類:DiaoSi
屌絲子類 - 按種類分類:ManDiaoSi,WomanDiao
屌絲子類 - 按特征分類:擁有黑木耳男屌絲,擁有擼管王的女屌絲,擁有紫木耳男屌絲,擁有擼神的女屌絲
行為實現 - Implementor:屌絲特征設置的行為類及子類
setFeatures:屌絲特征的設置接口
setFeatures黑木耳();
setFeatures紫木耳();
代碼:
package ITfarmer.designpatterns.study.bridge;
//測試
public class Client
{
public static void main( String[] argv )
{
Features 黑木耳= new 男屌絲特征();
Features 紫木耳= new 女屌絲特征();
DiaoSi 擁有黑木耳的男屌絲= new ManDiaoSi( 黑木耳 );
DiaoSi 擁有紫木耳的男屌絲= new ManDiaoSi( 紫木耳 );
擁有黑木耳的男屌絲.setFeatures();
擁有紫木耳的男屌絲.setFeatures();
DiaoSi 擁有黑木耳的女屌絲= new WomanDiao( 黑木耳 );
Vehicle 擁有紫木耳的女屌絲= new WomanDiao( 紫木耳 );
擁有黑木耳的女屌絲.setFeatures();
擁有紫木耳的女屌絲.setFeatures();
}
}
package ITfarmer.designpatterns.study.bridge;
*
* @author
* @since 2012/12/05
*/
public abstract class DiaoSi
{
private Features features;
Vehicle( Features features)
{
this.setFeatures ( features);
}
public abstract void setFeatures();
public void setFeatures( Features features)
{
this.features= features;
}
public Features getFeatures()
{
return features;
}
}
package ITfarmer.designpatterns.study.bridge;
//Abstraction子類:這里為屌絲抽象類的子類
public class ManDiaoSi extends DiaoSi
{
public ManDiaoSi (Features features
)
{
super( features
);
}
@Override
public void setFeatures()
{
System.out.print("男屌絲的特征: ");
getFeatures.setFeatures();
}
}
package ITfarmer.designpatterns.study.bridge;
//Abstraction子類:這里為屌絲抽象類的子類
public class WomanDiaoSi extends DiaoSi
{
public WomanDiaoSi ( Features features
)
{
super( features
);
}
@Override
public void setFeatures()
{
System.out.print("女屌絲的特征: ");
getFeatures().seFeatures();
}
}
package ITfarmer.designpatterns.study.bridge;
//屌絲類的行為接口
public interface Features
{
public void setFeatures();
}
package ITfarmer.designpatterns.study.bridge;
/** ConcreteImplementor */
//行為實現子類
public class 男屌絲特征 implements Features
{
public void setFeatures()
{
System.out.println("黑木耳 或者 擼管王");
}
}
package ITfarmer.designpatterns.study.bridge;
/** ConcreteImplementor */
//行為實現子類
public class 女屌絲特征 implements Features
{
public void setFeatures()
{
System.out.println("黑木耳 或者 擼管王");
}
}
小結:Bridge模式是一種抽象與其實現相分離的模式。它主要應用于:當事物是一組變化量,和對這些事物的操作方法(實現)也是一組變化量的情況,也就是說它們都是多變的。