生活中的一個例子:
就拿汽車在路上行駛的來講。即有小汽車又有公共汽車,它們都不但能在市區中的公路上行駛,也能在高速公路上行駛。這你會發現,對於交通工具(汽車)有不一樣的類型,然而它們所行駛的環境(路)也在變化,在軟件系統中就要適應兩個方面的變化?怎樣實現才能應對這種變化呢?
概述:
在軟件系統中,某些類型因爲自身的邏輯,它具備兩個或多個維度的變化,那麼如何應對這種「多維度的變化」?如何利用面嚮對象的技術來使得該類型可以輕鬆的沿着多個方向進行變化,而又不引入額外的複雜度?這就要使用Bridge模式。
意圖:
將抽象部分與實現部分分離,使它們均可以獨立的變化。
——《設計模式》GOF
結構圖:
傳統的作法:
經過類繼承的方式來作上面的例子;
先看一下類結構圖:
代碼實現:
設計模式
1namespace CarRunOnRoad
2{
3 //路的基類;
4 public class Road
5 {
6 public virtual void Run()
7 {
8 Console.WriteLine("在路上");
9 }
10 }
11 //高速公路;
12 public class SpeedWay : Road
13 {
14 public override void Run()
15 {
16 Console.WriteLine("高速公路");
17 }
18 }
19 //市區街道;
20 public class Street : Road
21 {
22 public override void Run()
23 {
24 Console.WriteLine("市區街道");
25 }
26 }
27 //小汽車在高速公路上行駛;
28 public class CarOnSpeedWay : SpeedWay
29 {
30 public override void Run()
31 {
32 Console.WriteLine("小汽車在高速公路上行駛");
33 }
34 }
35 //公共汽車在高速公路上行駛;
36 public class BusOnSpeedWay : SpeedWay
37 {
38 public override void Run()
39 {
40 Console.WriteLine("公共汽車在高速公路上行駛");
41 }
42 }
43 //小汽車在市區街道上行駛;
44 public class CarOnStreet : Street
45 {
46 public override void Run()
47 {
48 Console.WriteLine("汽車在街道上行駛");
49 }
50 }
51 //公共汽車在市區街道上行駛;
52 public class BusOnStreet : Street
53 {
54 public override void Run()
55 {
56 Console.WriteLine("公共汽車在街道上行駛");
57 }
58 }
59
60}ide
1static void Main(string[] args)
2 {
3 //小汽車在高速公路上行駛
4 CarOnSpeedWay Car = new CarOnSpeedWay();
5 Car.Run();
6
7 Console.WriteLine("===========================");
8
9 //公共汽車在街道上行駛
10 BusOnStreet Bus = new BusOnStreet();
11 Bus.Run();
12
13 Console.Read();
14 }工具
1namespace CarRunOnRoad_Bridge_
2{
3
4 //抽象路
5 public abstract class AbstractRoad
6 {
7 protected AbstractCar car;
8 public AbstractCar Car
9 {
10 set
11 {
12 car = value;
13 }
14 }
15
16 public abstract void Run();
17 }
18
19 //高速公路
20 public class SpeedWay : AbstractRoad
21 {
22 public override void Run()
23 {
24 car.Run();
25 Console.WriteLine("高速公路上行駛");
26 }
27 }
28
29 //市區街道
30 public class Street : AbstractRoad
31 {
32 public override void Run()
33 {
34 car.Run();
35 Console.WriteLine("市區街道上行駛");
36 }
37 }
38}spa
1namespace CarRunOnRoad_Bridge_
2{
3 //抽象汽車
4 public abstract class AbstractCar
5 {
6 public abstract void Run();
7 }
8
9 //小汽車;
10 public class Car : AbstractCar
11 {
12 public override void Run()
13 {
14 Console.Write("小汽車在");
15 }
16 }
17
18 //公共汽車
19 public class Bus : AbstractCar
20 {
21 public override void Run()
22 {
23 Console.Write("公共汽車在");
24 }
25 }
26}.net
客戶端調用:
設計
1 static void Main(string[] args)
2 {
3 //小汽車在高速公路上行駛;
4 AbstractRoad Road1 = new SpeedWay();
5 Road1.Car = new Car();
6 Road1.Run();
7 Console.WriteLine("=========================");
8
9 //公共汽車在高速公路上行駛;
10 AbstractRoad Road2 = new SpeedWay();
11 Road2.Car = new Bus();
12 Road2.Run();
13
14
15
16 Console.Read();
17 }3d
能夠看到,經過對象組合的方式,Bridge 模式把兩個角色之間的繼承關係改成了耦合的關係,從而使這二者能夠從容自若的各自獨立的變化,這也是Bridge模式的本意。
這樣增長了客戶程序與路與汽車的耦合。其實這樣的擔憂是沒有必要的,由於這種耦合性是因爲對象的建立所帶來的,徹底能夠用建立型模式去解決。在應用時結合建立型設計模式來處理具體的問題。
應用設計模式:
橋接模式(Bridge)來作(多維度變化);
結合上面的例子,增長一個維度"人",不一樣的人開着不一樣的汽車在不一樣的路上行駛(三個維度);
結合上面增長一個類"人",並從新調用.
代碼實現:
orm
1namespace CarRunOnRoad_Bridge_
2{
3 abstract class people
4 {
5 AbstractRoad road;
6 public AbstractRoad Road
7 {
8 get
9 {
10 return road;
11 }
12 set
13 {
14 road = value;
15 }
16 }
17 public abstract void Run();
18
19 }
20 class Man : people
21 {
22 public override void Run()
23 {
24 Console.Write("男人開着");
25 Road.Run();
26 }
27 }
28
29 class WoMan : people
30 {
31 public override void Run()
32 {
33 Console.Write("女人開着");
34 Road.Run();
35 }
36 }
37}對象
1 static void Main(string[] args)
2 {
3
4 //男人開着公共汽車在高速公路上行駛;
5 Console.WriteLine("=========================");
6
7 AbstractRoad Road3 = new SpeedWay();
8 Road3.Car = new Bus();
9
10 people p = new Man();
11 p.Road = Road3;
12 p.Run();
13
14 Console.Read();
15 }繼承
效果及實現要點:
1.Bridge模式使用「對象間的組合關係」解耦了抽象和實現之間固有的綁定關係,使得抽象和實現能夠沿着各自的維度來變化。
2.所謂抽象和實現沿着各自維度的變化,即「子類化」它們,獲得各個子類以後,即可以任意它們,從而得到不一樣路上的不一樣汽車。
3.Bridge模式有時候相似於多繼承方案,可是多繼承方案每每違背了類的單一職責原則(即一個類只有一個變化的緣由),複用性比較差。Bridge模式是比多繼承方案更好的解決方法。
4.Bridge模式的應用通常在「兩個很是強的變化維度」,有時候即便有兩個變化的維度,可是某個方向的變化維度並不劇烈——換言之兩個變化不會致使縱橫交錯的結果,並不必定要使用Bridge模式。
適用性:
在如下的狀況下應當使用橋樑模式:
1.若是一個系統須要在構件的抽象化角色和具體化角色之間增長更多的靈活性,避免在兩個層次之間創建靜態的聯繫。
2.設計要求實現化角色的任何改變不該當影響客戶端,或者說實現化角色的改變對客戶端是徹底透明的。
3.一個構件有多於一個的抽象化角色和實現化角色,系統須要它們之間進行動態耦合。
4.雖然在系統中使用繼承是沒有問題的,可是因爲抽象化角色和具體化角色須要獨立變化,設計要求須要獨立管理這二者。
總結:
Bridge模式是一個很是有用的模式,也很是複雜,它很好的符合了開放-封閉原則和優先使用對象,而不是繼承這兩個面向對象原則。
橋接模式與裝飾的區別:
裝飾模式:
這兩個模式在必定程度上都是爲了減小子類的數目,避免出現複雜的繼承關係。可是它們解決的方法卻各有不一樣,裝飾模式把子類中比基類中多出來的部分放到單獨的類裏面,以適應新功能增長的須要,當咱們把描述新功能的類封裝到基類的對象裏面時,就獲得了所須要的子類對象,這些描述新功能的類經過組合能夠實現不少的功能組合 .
橋接模式: 橋接模式則把原來的基類的實現化細節抽象出來,在構造到一個實現化的結構中,而後再把原來的基類改形成一個抽象化的等級結構,這樣就能夠實現系統在多個維度上的獨立變化