桥接模式(Bridge Pattern)
- 桥接模式概述
定义:将抽象部分与它的实现部分解耦,使得两者都能够独立的变化
就拿我们日常使用的蜡笔来说,蜡笔有不同的大小和颜色,所以我们往往买的蜡笔盒中会有不少的蜡笔。需要用哪个就用哪个,是不是很方便???然而毛笔却不是这样,毛笔分为不同大小,却只有一个调色盘,里面装着不同的颜料。我们需要什么用到什么,就用对应大小的毛笔去蘸对应的颜料。二者想比,哪个更方便呢??我倒是觉得还是蜡笔方便,但是,试想一下,如果我们笔的大小变化有很多,颜色我也要越多越好,以应对变化。那么,我们的蜡笔可能就会多到难以想象,而毛笔只要提供对对应大小的毛笔,颜色只要放到调色盘里就OK了。这样,我们只要带着笔和调色盘就好了,这比带着许多只蜡笔可要方便多了吧。桥接模式,就是要像毛笔这样应对不同(多维度)变化而来的。
桥接模式是一种对象结构性模式,又被称为柄体(Handle and Body)模式或接口(Interface)模式。
- 桥接模式的结构
- Abstraction(抽象类):定义抽象类的接口,通常是抽象类而不是接口,其中定义Implementor(实现类接口)类型的对象并维护该对象,与Implementor之间是关联关系
- RefinedAbstraction(扩展抽象类):扩充Abstraction定义的接口,实现了在Abstraction中声明的抽象业务方法,在RefinedAbstraction中调用在Implementor中定义的方法
- Implementor(实现类接口):定义实现类的接口,仅提供基本操作,在子类中具体实现。并通过关联关系,在Abstraction中不仅调用自己的方法,也可以调用Implementot的方法
- ConcreteImplementor(具体实现类):具体实现Implementor接口,在不同的子类中提供基本操作的不同实现
- 接口类:
1 interface Implementor 2 { 3 void OperationImpl(); 4 }
- ConcreteImplementor类:
1 class ConcreteImplementor:Implementor 2 { 3 public void OperationImpl() 4 { 5 //Specific Business Realization 6 } 7 }
- Abstraction类:
1 abstract class Abstraction 2 { 3 protected Implementor impl; 4 public void SetImpl(Implementor impl) 5 { 6 this.impl = impl; 7 } 8 9 public abstract void Operation(); 10 }
- RefinedAbstraction类:
1 class RefinedAbstraction : Abstraction 2 { 3 public override void Operation() 4 { 5 //Business methods 6 impl.OperationImpl(); 7 //Business methods 8 } 9 }
上述图可能不那么容易理解,我们看下毛笔的结构示意图:
大小和颜色是两个维度,所以毛笔类为抽象类,在Brush类中声明并部分实现毛笔的业务方法,而将各种型号的毛笔作为其子类;颜色与毛笔存在“设置颜色”的关系,所以提供一个颜色接口,而将具体的颜色作为接口的子类。这样,型号的扩展和颜色扩展即可独立,二者又是关联的,方便扩展
注意:color设为protected是为了只让自己的子类才可以使用
应用实例
空客(Airbus)、播音(Boeing)和麦道(McDonnell-Douglas)都是飞机制造商,他们都生产载客飞机(Passenger Plane)和载货飞机(Cargo Plane)。设计一个系统,实现他们
分析:飞机制造商是一个变化点,我们可以定义一个Plane抽象类,它的子类就是各种飞机制造商,类中有抽象Create方法,再定义一个KindofPlane接口,它有CreatePlane的方法,不同类型的飞机种类实现接口方法,这是第二个变化点,Plane和接口关联,桥接起来。
结构:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 6 namespace BridgePattern 7 { 8 interface KindofPlane//Implementor 9 { 10 void CreatePlane(); 11 } 12 class PassengerPlane : KindofPlane//ConcreteImplementorA 13 { 14 15 public void CreatePlane() 16 { 17 Console.WriteLine("Create Passenger Plane"); 18 } 19 } 20 class CargoPlane : KindofPlane//ConcreteImplementorB 21 { 22 23 public void CreatePlane() 24 { 25 Console.WriteLine("Create Cargo Plane"); 26 } 27 } 28 abstract class Plane//Abstraction 29 { 30 protected KindofPlane planekind; 31 public void setkind(KindofPlane planekind) 32 { 33 this.planekind = planekind; 34 } 35 public abstract void Create(); 36 37 } 38 class Airbus : Plane//RefinedAbstraction 39 { 40 public override void Create() 41 { 42 Console.WriteLine("Airbus:"); 43 planekind.CreatePlane(); 44 } 45 } 46 class Boeing : Plane//RefinedAbstraction 47 { 48 public override void Create() 49 { 50 Console.WriteLine("Boeing:"); 51 planekind.CreatePlane(); 52 } 53 } 54 class McDonnell_Douglas : Plane//RefinedAbstraction 55 { 56 public override void Create() 57 { 58 Console.WriteLine("McDonnell_Douglas:"); 59 planekind.CreatePlane(); 60 } 61 } 62 class Program 63 { 64 static void Main(string[] args) 65 { 66 Console.WriteLine("~~~~~~~~~~~~~~~~~~~~~~~~~~~"); 67 KindofPlane passengerPlane = new PassengerPlane(); 68 Airbus air = new Airbus(); 69 air.setkind(passengerPlane); 70 air.Create(); 71 Console.WriteLine("~~~~~~~~~~~~~~~~~~~~~~~~~~~"); 72 KindofPlane cargoPlane = new CargoPlane(); 73 Boeing boe = new Boeing(); 74 boe.setkind(cargoPlane); 75 boe.Create(); 76 Console.WriteLine("~~~~~~~~~~~~~~~~~~~~~~~~~~~"); 77 KindofPlane cargpPlane2 = new CargoPlane(); 78 McDonnell_Douglas mc= new McDonnell_Douglas(); 79 mc.setkind(cargoPlane); 80 mc.Create(); 81 Console.WriteLine("~~~~~~~~~~~~~~~~~~~~~~~~~~~"); 82 } 83 } 84 }
- 桥接模式的优点
- 分离抽象接口及其实现部分,从而可以获得更多维度组合对象。即可以搭建很多的桥
- 桥接模式可取代多层继承方案,极大减少了子类的个数
- 提高了系统的可扩展性,多维度间任意扩展需要扩展的一个维度,不需修改原有系统,符合开闭原则
- 桥接模式的缺点
- 会增加系统的理解与设计难度,需要对抽象层进行编程
- 要正确的分别出独立变化的维度,使其使用范围有一定局限性
- 桥接模式的适用环境
- 如果一个系统需要在抽象化和具体化之间增加更多的灵活性,避免在两个层次间建立静态的继承关系,可以用桥接模式在抽象层建立关联关系
- 抽象部分和实现部分可以以继承的方式独立扩展而不互相影响,系统需要对抽象化角色和实现化角色进行动态耦合
- 一个类存在两个或多个独立变化的维度,且各自需要独立的进行扩展
- 对于不希望使用继承或因为多层继承导致系统类的个数急剧增加的系统,桥接模式很适用