GOF设计模式之桥接模式
引入
现需要提供能够绘制4种不同颜色且笔画粗细有大中小3种型号的画笔。
方法一:蜡笔
我们需要准备3*4=12支蜡笔,也就是说必须准备12个具体的蜡笔类
方法二:毛笔
只需要准备三种型号的毛笔,外加四个颜料盒,用3+4=7个类就可以实现12支蜡笔的功能
定义
桥接模式的定义:将抽象与实现分离,使它们可以独立变化。它是用关联关系代替继承关系来实现,从而降低了抽象和实现这两个可变维度的耦合度。
实现
基础实现
//实现化角色 interface Implementor { public void OperationImpl(); } //具体实现化角色 class ConcreteImplementorA implements Implementor { public void OperationImpl() { System.out.println("具体实现化(Concrete Implementor)角色被访问" ); } } //抽象化角色 abstract class Abstraction { protected Implementor imple; protected Abstraction(Implementor imple) { this.imple=imple; } public abstract void Operation(); } //扩展抽象化角色 class RefinedAbstraction extends Abstraction { protected RefinedAbstraction(Implementor imple) { super(imple); } public void Operation() { System.out.println("扩展抽象化(Refined Abstraction)角色被访问" ); imple.OperationImpl(); } } //测试类 public class BridgeTest { public static void main(String[] args) { Implementor imple=new ConcreteImplementorA(); Abstraction abs=new RefinedAbstraction(imple); abs.Operation(); } }
画笔实现
优缺点
优点:
分离抽象接口及其实现部分。
桥接模式有时类似于多继承方案,但是多继承方案违背了类的单一职责原则(即一个类只有一个变化的原因),复用性比较差,而且多继承结构中类的个数非常庞大,桥接模式是比多继承方案更好的解决方法。
桥接模式提高了系统的可扩充性,在两个变化维度中任意扩展一个维度,都不需要修改原有系统。
实现细节对客户透明。
缺点:
桥接模式的引入会增加系统的理解与设计难度,由于聚合关联关系建立在抽象层,要求开发者针对抽象进行设计与编程。
桥接模式要求正确识别出系统中两个独立变化的维度,因此其使用范围具有一定的局限性。
使用场景
如果一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性,避免在两个层次之间建立静态的继承联系,通过桥接模式可以使它们在抽象层建立一个关联关系。
对于那些不希望使用继承或因为多层次继承导致系统类的个数急剧增加的系统,桥接模式尤为适用。
一个类存在两个独立变化的维度,且这两个维度都需要进行扩展。
典型应用
JDBC
String sql = "具体要操作的sql语句"; // 1:装载驱动 Class.forName("驱动的名字"); // 2:创建连接 Connection conn = DriverManager.getConnection("连接数据库服务的URL", "用户名","密码"); // 3:创建statement或者是preparedStatement PreparedStatement pstmt = conn.prepareStatement(sql); // 4:执行sql,如果是查询,再获取ResultSet ResultSet rs = pstmt.executeQuery(sql); // 5:循环从ResultSet中把值取出来,封装到数据对象中去 while (rs.next()) { // 取值示意,按名称取值 String uuid = rs.getString("uuid"); // 取值示意,按索引取值 int age = rs.getInt(2); } //6:关闭 rs.close(); pstmt.close(); conn.close();
我们写的应用程序,是面向JDBC的API在开发,这些接口就相当于桥接模式中的抽象部分的接口。JDBC的驱动程序实现了JDBC的API,驱动程序就相当于桥接模式中的具体实现部分。DriverManager来把它们桥接起来,从某个侧面来看,DriverManager在这里起到了类似于简单工厂的功能。
该例子详情可见:
https://www.jianshu.com/p/af6b1b27f638
介绍了广义桥接模式和更多其他模式对比
对比
策略模式 - 相同点:
在桥接模式中,Abstraction通过聚合的方式引用Implementor。
在策略模式中,Context也使用聚合的方式引用Startegy抽象接口。
在这两种模式中,都存在一个对象使用聚合的方式引用另一个对象的抽象接口的情况,而且该抽象接口的实现可以有多种并且可以替换。可以说两者在表象上都是调用者与被调用者之间的解耦,以及抽象接口与实现的分离。
策略模式 - 不同点:
在形式上,在桥接模式中不仅Implementor具有变化(ConcreateImplementior),而且Abstraction也可以发生变化(RefinedAbstraction),且两者的变化是完全独立的,RefinedAbstraction与ConcreateImplementior之间松散耦合,它们仅仅通过Abstraction与Implementor之间的关系联系起来。而在策略模式中,并不考虑Context的变化,只有算法的可替代性。
在语意上,桥接模式强调Implementor接口仅提供基本操作,而Abstraction则基于这些基本操作定义更高层次的操作。而策略模式强调Strategy抽象接口的提供的是一种算法,一般是无状态、无数据的,而Context则简单调用这些算法完成其操作。
适配器模式 - 相同点:
让两个东西配合工作,且和对象适配器模式一样,都存在一个类调用另一个类。
适配器模式 - 不同点:
假如A适配B(只针对对象的适配器),以及A桥接B
时机:适配是在A,B都早已实现的情况下,而桥接反之,设计之初就要考虑
动机:适配是A为了满足B接口的需求封装自己迎合B,桥接是AB两个维度共同组合成一个实体。
装饰器模式 - 相同点:
使得两者可以独立变化。可以减少派生类的增长。
装饰器模式 - 不同点:
装饰是实现与实现之间的动态组合。
桥接是抽象与实现的分离。