java设计模式|java设计模式——结构型之桥接模式

自大学课程初识设计模式以来,就越发觉得有必要系统学习一下设计模式。 刚好在实习前准备期间课比较少,抽出一点时间整理一下记一些笔记,复制粘贴比较多。 笔记比较适合学习过设计模式的同学。

Bridge Pattern(桥接模式) 学习链接:极客学院Wiki_Java设计模式之结构型模式 另外感谢刘伟博士,学习设计模式可以看刘伟博士的博客,很详尽。
刘伟技术博客 桥接模式的适用范围 (1)如果一个系统需要在抽象化和具体化之间增加更多的灵活性,避免在两个层次之间建立静态的继承关系,通过桥接模式可以使它们在抽象层建立一个关联关系。
(2)“抽象部分”和“实现部分”可以以继承的方式独立扩展而互不影响,在程序运行时可以动态将一个抽象化子类的对象和一个实现化子类的对象进行组合,即系统需要对抽象化角色和实现化角色进行动态耦合。
(3)一个类存在两个(或多个)独立变化的维度,且这两个(或多个)维度都需要独立进行扩展。
(4)对于那些不希望使用继承或因为多层继承导致系统类的个数急剧增加的系统(类爆炸),桥接模式尤为适用。
应用实例 桥接模式是设计 Java 虚拟机和实现 JDBC 等驱动程序的核心模式之一,应用较为广泛。
桥接模式如何实现 角色
Abstraction(抽象类) 用于定义抽象类的接口,它一般是抽象类而不是接口,其中定义了一个 Implementor(实现类接口)类型的对象并可以维护该对象,它与 Implementor 之间具有关联关系,它既可以包含抽象业务方法,也可以包含具体业务方法。
RefinedAbstraction(扩充抽象类) 扩充由 Abstraction 定义的接口,通常情况下它不再是抽象类而是具体类,它实现了在 Abstraction 中声明的抽象业务方法,在 RefinedAbstraction 中可以调用在 Implementor 中定义的业务方法。
Implementor(实现类接口) 定义实现类的接口,这个接口不一定要与 Abstraction 的接口完全一致,事实上这两个接口可以完全不同,一般而言,Implementor 接口仅提供基本操作,而 Abstraction 定义的接口可能会做更多更复杂的操作。Implementor 接口对这些基本操作进行了声明,而具体实现交给其子类。通过关联关系,在 Abstraction 中不仅拥有自己的方法,还可以调用到 Implementor 中定义的方法,使用关联关系来替代继承关系。
ConcreteImplementor(具体实现类) 具体实现 Implementor 接口,在不同的 ConcreteImplementor 中提供基本操作的不同实现,在程序运行时,ConcreteImplementor 对象将替换其父类对象,提供给抽象类具体的业务操作方法。
类图
java设计模式|java设计模式——结构型之桥接模式
文章图片

桥接模式在类图和定义中比较难理解,这里的抽象和实现不是一般我们说设计模式的抽象和实现。放到实例之中就会好理解很多。
一般我们会将桥接模式和适配器模式放在一起使用,因为经常会出现需要调用第三方类库的功能。
桥接模式和适配器模式合作
java设计模式|java设计模式——结构型之桥接模式
文章图片

如图就是一个很典型的例子。
桥接模式的优缺点 主要优点
(1)分离抽象接口及其实现部分。
桥接模式使用“对象间的关联关系”解耦了抽象和实现之间固有的绑定关系,使得抽象和实现可以沿着各自的维度来变化。所谓抽象和实现沿着各自维度的变化,也就是说抽象和实现不再在同一个继承层次结构中,而是“子类化”它们,使它们各自都具有自己的子类,以便任何组合子类,从而获得多维度组合对象。
(2)在很多情况下,桥接模式可以取代多层继承方案,多层继承方案违背了“单一职责原则”,复用性较差,且类的个数非常多,桥接模式是比多层继承方案更好的解决方法,它极大减少了子类的个数。
(3)桥接模式提高了系统的可扩展性,在两个变化维度中任意扩展一个维度,都不需要修改原有系统,符合“开闭原则”。
主要缺点
(1)桥接模式的使用会增加系统的理解与设计难度,由于关联关系建立在抽象层,要求开发者一开始就针对抽象层进行设计与编程。
【java设计模式|java设计模式——结构型之桥接模式】(2)桥接模式要求正确识别出系统中两个独立变化的维度,因此其使用范围具有一定的局限性,如何正确识别两个独立维度也需要一定的经验积累。
练习 题目
Sunny 软件公司欲开发一个数据转换工具,可以将数据库中的数据转换成多种文件格式,例如 txt、xml、pdf 等格式,同时该工具需要支持多种不同的数据库。试使用桥接模式对其进行设计。
题目分析
工具的主要两个模块是转换成多种文件格式,从不同数据库中调取数据,对于这个题目,我的理解是将转换作为抽象,访问不同数据库中的数据作为具体实现。
实现代码
抽象类:ChangeTools.java
package com.joy; public abstract class ChangeTools {protected DataBase db; public void setDataBase(DataBase db){ this.db = db; } public abstract void changeFiles(); }

扩充抽象类:ChangeToTXT.java
package com.joy; public class ChangeToTXT extends ChangeTools { @Override public void changeFiles() { db.getDate(); System.out.println("将数据保存成txt文件……"); } }

扩充抽象类:ChangeToXML.java
package com.joy; public class ChangeToXML extends ChangeTools { @Override public void changeFiles() { db.getDate(); System.out.println("将数据保存成xml文件……"); } }

扩充抽象类:ChangeToPDF.java
package com.joy; public class ChangeToPDF extends ChangeTools { @Override public void changeFiles() { db.getDate(); System.out.println("将数据保存成pdf文件……"); } }

实现类接口:DataBase.java
package com.joy; public interface DataBase { public void getDate(); }

具体实现类:DB2DataBase.java
package com.joy; public class DB2DataBase implements DataBase {@Override public void getDate() { System.out.println("访问DB2数据库:从中调取数据"); }}

具体实现类:MySQLDataBase.java
package com.joy; public class MySQLDataBase implements DataBase {@Override public void getDate() { System.out.println("访问MySQL数据库:从中调取数据"); }}

客户端:Clien.java
package com.joy; public class Client { public static void main(String[] args) { ChangeTools cts; //数据库为DB2 DataBase db= new DB2DataBase(); cts = new ChangeToTXT(); cts.setDataBase(db); cts.changeFiles(); //数据库改成MySQL db = new MySQLDataBase(); cts.setDataBase(db); cts.changeFiles(); //转换成PDF格式 cts = new ChangeToPDF(); cts.setDataBase(db); cts.changeFiles(); } }

运行结果
java设计模式|java设计模式——结构型之桥接模式
文章图片

总结 桥接模式是一个非常有用的模式,在桥接模式中体现了很多面向对象设计原则的思想,包括“单一职责原则”、“开闭原则”、“合成复用原则”、“里氏代换原则”、“依赖倒转原则”等。熟悉桥接模式有助于我们深入理解这些设计原则,也有助于我们形成正确的设计思想和培养良好的设计风格。

    推荐阅读