1 基础知识
1.1 标准定义
桥接(Bridge)模式标准定义:将抽象部分与它的实现部分分离,使它们都可以独立地变化。
1.2 分析和说明
桥接(Bridge)模式属于结构型设计模式。它将抽象化与实现化脱耦,使得二者可以独立的变化,也就是说将他们之间的强关联变成弱关联,也就是指在一个软件系统的抽象化和实现化之间使用组合/聚合关系而不是继承关系,从而使两者可以独立的变化。
Bridge结构如图1所示。Bridge角色包括抽象化(Abstraction)角色、修正抽象化(Refine Abstraction)角色、实现化(Implementor)角色和具体实现化(Concrete Implementor)角色。
图1 桥接模式结构
抽象化(Abstraction)角色:Abstraction定义抽象类的接口。维护一个指向Implemcntor类型对象的指针。抽象化(Abstraction)角色可以是接口,也可以是抽象类。属于不可缺少角色。
修正抽象化(Refine Abstraction)角色:RefinedAbstraction扩充由Abstraction定义的接口 Implementor定义实现类的接口。该接口不一定要与Abstraction的接口完全一致。
实现化(Implementor)角色:lmplementor接口仅提供基本操作。这个抽象类规范具体实现化角色,规定出具体实现化角色当有的(非私有)方法和属性。实现化(Implementor)角色可以是接口,也可以是抽象类。属于不可缺少角色。
具体实现化(Concrete Implementor)角色:Concreteimplementor实现Implementor接口并定义它的具体实现。
2 应用场景举例
比如公司有几个技术部门,分别是研发部、开发部和售后服务部。这些部门都有培训和开会等工作。培训的时候,要有培训老师、培训教材、培训人员和培训教室。对于开会也是一样的,有开会的主持人、开会地点等。所以,可以把部门理解为抽象单位,研发部、开发部和售后服务部继承抽象单位并实现具体的工作。日常工作可以抽象起来,培训和开会继承日常工作,不同的部门的日常工作是不同的。其用例图如图2所示。
图2 桥接模式用例图
在这里可以把AbstractDepartment类理解为抽象化(Abstraction)角色。AbstractAction类是实现化(Implementor)角色。DevelopmentDep类、FinanceDep类和MarketDep理解为修正抽象化(Refine Abstraction)角色。Meeting类和Training类理解为具体实现化(Concrete Implementor)角色。其结构类图如图3所示。
图3 桥接模式类图
桥接模式实现的顺序图如图4所示,实现顺序描述:
①创建一个活动对象;
②创建一个部门对象;
③-④把活动对象赋值给部门对象;
⑤显示部门对象的活动情况。
图4 桥接模式实现顺序图
活动对象可以分为会议对象和培训对象,部门对象可以是技术部门对象,财务部门对象和市场部门对象,所以两个类型可以自己内部转化,只是通过他们的抽象类或接口实现了扩充和复用。即技术部门对象可以实现会议对象和培训对象的工作。财务部门对象和市场部门对象也可以实现会议对象和培训对象的工作。使得活动和部门二者可以独立的变化。
3.Java的实现程序代码
Java程序实现主要包括AbstractAction抽象类文件、AbstractDepartment抽象类文件、DevelopmentDep类文件、FinanceDep类文件、MarketDep类文件、Meeting类文件和Training类文件等6个文件。其关系如图3所示。下面分别列出这6个文件的程序代码,最后列出测试代码并显示输出结果。
AbstractAction抽象类是实现化(Implementor)角色。其类程序代码清单01所示。
程序代码清单01
public abstract class AbstractAction { public void doAction(String depart, String title) { if (depart.length() == 0) System.out.println("这是部门的标准工作活动"); System.out.println("这是" + depart + "部门的标准工作活动," + "主题是" + title); } } |
AbstractDepartment抽象类理解为抽象化(Abstraction)角色,其程序代码清单02所示。
程序代码清单02
public abstract class AbstractDepartment { protected AbstractAction departAction; public void setAbstractAction(AbstractAction action) { departAction = action; } public void action(String title) { departAction.doAction("", title); } } |
DevelopmentDep类、FinanceDep类和MarketDep类继承AbstractDepartment类,其类程序代码清单03所示。
程序代码清单03
public class DevelopmentDep extends AbstractDepartment { private String departName = "开发部"; public void action(String title) { departAction.doAction(departName, title); } } public class FinanceDep extends AbstractDepartment { private String departName = "财务部"; public void action(String title) { departAction.doAction(departName, title); } } public class MarketDep extends AbstractDepartment { private String departName = "市场部"; public void action(String title) { departAction.doAction(departName, title); } } |
Meeting类和Training类继承AbstractAction抽象类,其类程序代码清单04所示。
程序代码清单04
public class Meeting extends AbstractAction { public void doAction(String depart, String title) { if (depart.length() == 0) { System.out.println("这是部门的会议工作活动"); } System.out.println("这是" + depart + "会议工作活动," + "主题是" + title); } } public class Training extends AbstractAction { public void doAction(String depart, String title) { if (depart.length() == 0) { System.out.println("这是部门的培训工作活动"); } System.out.println("这是" + depart + "培训工作活动," + "主题是" + title); } } |
桥梁模式测试程序的代码清单05如下:
程序代码清单05
public class Client { public static void scene1() { // 场景1:针对开发部的培训工作 AbstractAction action = new Training(); AbstractDepartment depart = new DevelopmentDep(); depart.setAbstractAction(action); depart.action("提高开发技能"); } public static void scene2() { // 场景2:针对财务部的会议 AbstractAction action = new Meeting(); AbstractDepartment depart = new FinanceDep(); depart.setAbstractAction(action); depart.action("检查会计制度"); } public static void scene3() { // 场景2:针对市场部的培训 AbstractAction action = new Training(); AbstractDepartment depart = new MarketDep(); depart.setAbstractAction(action); depart.action("沟通技巧"); } public static void main(String[] args) { scene1(); scene2(); scene3(); } } |
桥梁模式测试类输出结果如下所示:
这是开发部培训工作活动,主题是提高开发技能 这是财务部会议工作活动,主题是检查会计制度 这是市场部培训工作活动,主题是沟通技巧 |
4 扩展和说明
JDK中的AWT就是采用的桥梁模式实现。
Component是提供给开发人员对窗体界面系统的抽象,代表图形用户界面中的一个控件,对于事件响应的处理,在Component类中有ComponentEvent属性。但是,在具体实现中,针对不同的Component类型,有着不同Event事件响应。例如,如果你使用AWT创建了一个Window类的实例,那么在程序运行时会创建一个窗口的实例,而由窗口实例会产生WindowEvent响应。不同的组件,有不同的事件响应实现。所以,作为Component有自己的一套继承体系,而Event事件响应也有对应的继承体系。而Component通过关联Event把这两者结合起来,形成这种一一映射关系。其实现结构见图5所示。
图5 JDK中Component和ComponentEvent桥接类结构图
实际上,从设计的角度来看,这是一个抽象和实现分离的过程。Component和ComponentEvent是抽象,Container和ContainerEvent是具体实现,抽象和实现各自成为一个对象体系,它们由一个桥连接起来,可以各自发展各自的对象层次,而不必顾虑另一方面。这就是Bridge模式所提供的思想。
参考链接
7种结构型模式:
Gof23种设计模式(6)——适配器模式(Adapter)
Gof23种设计模式(7)——桥接模式(Bridge)
Gof23种设计模式(8)——组合模式(Composite)
Gof23种设计模式(9)——装饰器模式(Decorator)
Gof23种设计模式(10)——外观模式(Facade)
Gof23种设计模式(11)——享元模式(Flyweight)
Gof23种设计模式(12)——代理模式(Proxy)
Gof23种设计模式 —— 结构型模式总结和比较
回到总目录:Gof23种设计模式(全解析)
(转载自微信公众号:架构设计模式)