橋接模式的動機
假設我們有一個坦克游戲的開發,那麼這個坦克有多種類型,並且這個游戲要支持多種平台的游戲
事實上由於Tank類型的固有邏輯,使得Tank類型具有了兩個變化的維度--一個變化的維度為"平台的變化",一個變化的維度為"型號的變化"。如何應對這種"多維度的變化"?如何利用面向對象技術來使得Tank類型可以輕松地沿著"平台"和"型號"兩個方向變化,而不引入額外的復雜度?
橋接模式的意圖
將抽象部分與實現部分分離,使它們都可以獨立地變化。
下面用代碼來實現
public abstract class Tank
...{
protected TankPlatformImplementation tankImp;
public Tank(TankPlatformImplementation tankImp)
...{
this.tankImp = tankImp;
}
public TankPlatformImplementation TanImp
...{
get
...{
return this.tankImp;
}
set
...{
this.tankImp = value;
}
}
public abstract void Shot();
public abstract void Run();
public abstract void Stop();
}
這是一個坦克的抽象基類,它是比較穩定的,表明坦克的類型,我們現在先不看TankPlatformImplementation,在後面來敘述它。
如果我們要這個坦克有多種類型的坦克,並且也支持多個平台,那麼我們會有一個種類的坦克繼承於Tank類型,然後還要有這種類型坦克的各個平台的坦克繼承於這種坦克類型,那麼我們有n種坦克,就會有n × 2種實現平台的坦克類型,那麼我們需要隔離這種變化。我們將平台不用繼承,使用組合,將平台和坦克種類隔離開來。
現在看看坦克類型
public class TankT50 : Tank
...{
public TankT50(TankPlatformImplementation tankImp)
: base(tankImp)
...{
}
public override void Shot()
...{
tankImp.DOShot();
}
public override void Run()
...{
tankImp.MoveTank(new Point());
}
public override void Stop()
...{
//tankImp....;
}
}
public class TankT75 : Tank
...{
public TankT75(TankPlatformImplementation tankImp)
: base(tankImp)
...{
}
public override void Shot()
...{
tankImp.DOShot();
}
public override void Run()
...{
tankImp.MoveTank(new Point());
}
public override void Stop()
...{
//tankImp....;
}
}
public class TankT90 : Tank
...{
public TankT90(TankPlatformImplementation tankImp)
: base(tankImp)
...{
}
public override void Shot()
...{
tankImp.DOShot();
}
public override void Run()
...{
tankImp.MoveTank(new Point());
}
public override void Stop()
...{
//tankImp....;
}
}
那麼我們在坦克種類實現的時候,使用平台類型來表現出坦克的使用。
下面看看坦克平台是如何實現
public abstract class TankPlatformImplementation
...{
public abstract void MoveTank(Point to);
public abstract void DrawTank();
public abstract void DOShot();
}
這是一個坦克平台的抽象類,規定了在各種平台下坦克需要作的動作
public class PCTankImplementation : TankPlatformImplementation
...{
public override void MoveTank(Point to)
...{
}
public override void DrawTank()
...{
}
public override void DOShot()
...{
}
}
public class MobileTankImplementation : TankPlatformImplementation
...{
public override void MoveTank(Point to)
...{
}
public override void DrawTank()
...{
}
public override void DOShot()
...{
}
}
那麼我們在各種平台下的動作由各種平台的派生類來實現。我們可以看出平台類作為一個橋接,將另一個緯度的變化轉換了。
那麼我們如何創建一個坦克類型
static void Main(string[] args)
...{
MobileTankImplementation imp = new MobileTankImplementation();
TankT50 tank = new TankT50(imp);
}
我們可以先規定游戲運行的平台,使用當前平台來使用坦克種類在各種平台殺那個的表現。
Bridge模式的幾個要點
- Bridge模式使用"對象間的組合關系"解耦了抽象和實現之間固有的綁定關系,使得抽象(Tank的型號)和實現(不同的平台)可以沿著各自的維度來變化。
- 所謂抽象和實現沿著各自緯度的變化,即"子類化"它們,比如不同的Tank型號子類,和不同的平台子類)。得到各個子類之後,便可以任意組合它們,從而獲得不同平台上的不同型號。
- Bridge模式有時候類似於多繼承方案,但是多繼承方案往往違背單一職責原則(即一個類只有一個變化的原因),復用性比較差。Bridge模式是比多繼承方案更好的解決方法。
- Bridge模式的應用一般在"兩個非常強的變化維度",有時候即使有兩個變化的維度,但是某個方向的變化維度並不劇烈--換言之兩個變化不會導致縱橫交錯的結果,並不一定要使用Bridge模式。