1.意图
“将抽象部分与它的实现部分分离,使它们都可以独立地变化”,这是GOF在《设计模式》一书中的解释。这里的抽象和实现并不一定是同一层次的概念,例如数据库操作可以归结为“增加、删除和修改”。很多业务过程都是通过对数据库的操作实现的,例如“库存管理”中的“入库”,这个业务动作的软件实现可以描述为“在库存表中增加一条记录”,而“入库”和“插入记录”处于不同的业务层次。
2.使用场合
在如下情况下可以使用桥接模式。
(1)不希望在业务和业务的软件实现之间存在因定的绑定关系。例如,不希望“入库”业务过程和具体的数据库访问技术或数据库管理系统有过于密切的关系。最好是数据库访问技术的升级,或数据库管理系统的改变对业务模块没有影响,甚至在运行期间可以通过动态绑定来选择不同数据库技术或数据库管理系统。
(2)希望类的抽象和实现部分可以扩充,进而实现不同的抽象接口和实现部分的组合。
(3)修改实现部分对用户不产生影响,即代码无须重新编译。
(4)复用实现部分。由于实现部分所处的层次较低,因此可以被多种业务模块复用。例如,数据库访问模块可以用在多种业务单元中。
3.结构
桥接模式的结构如图所示。
(1)Abstraction:定义抽象类的接口并维护指向Implementor类的对象指针。
(2)RefinedAbstraction:扩充Abstraction定义的接口。
(3)Implementor:定义实现类的接口,该接口不一定要与Abstraction的接口完全一致。
事实上这两个接口可以完全不同。一般而言,Implementor接口仅提供基本操作,而Abstraction则定义了基于操作的较高层次的操作。
(4) ConcreteImplementor:实现Implementor接口并定义它的具体实现。
为了更深入了解这个模式,我们来看一个具体的例子。在应用系统中经常有很多业务单元在很多业务模块中类似,隐含在背后的业务域模型相同。例如,“设备管理”中的“零部件管理”,“物资管理”中的“库房管理”,“实验室管理”中的“试剂管理”等都是“库存管理”。但由于业务场景的不同,导致业务中的细节不同,因此不能简单地复用。另外,“库存管理”软件的实现主要通过操作关系数据库来完成,我们希望保持软件系统与数据库访问技术以及数据库管理系统的独立性。
为了实现以上要求,我们可以以桥接模式。即将抽象的“库存管理”和“数据库”操作作为具体的“库存管理”应用和具体的“数据库访问技术”的桥梁, 如下图所示。
从图中可以看出,我们将库存管理的抽象业务域模型封装在“抽象的库存管理”中。具体的库存管理业务如“生产车间库存管理”可以通过继承库存管理获得一般性的业务过程,然后根据具体的业务特点进行相应的扩展。
我们将数据库操作封装在dbOperation类中,具体执行访问数据库的各个指令,针对具体数据库的操作由该类的子类实现。
4.效果
采用桥接模式可以获得以下好处。
(1)将接口与实现分离:一个接口可以有若干实现,一个实现也可以为若干对象服务,表示逻辑的对象可以动态地与实现功能的对象组合。
(2)提高可扩充性:逻辑和实现都可以通过类层次的扩展进行扩充。
需要注意的是,逻辑和实现被封装在不同的对象中,逻辑对实现的引用是动态进行的。在实际中,需要分别用不同的工厂创建逻辑和实现,然后组装。