桥接(Bridge)模式
先举个现实生活中的例子,现在对不同手机类型的不同品牌实现操作编程(比如:开机、关机、上网、打电话等),如图:
如果用传统方式如何解决呢?
我们可以看到,使用传统方式解决手机操作问题会存在下列问题:
-
扩展性问题(类爆炸),如果我们再增加手机的样式(旋转式),就需要增加各个品牌手机的类,同样如果我们增加一个手机品牌,也要在各个手机样式类下增加
-
违反了单一职责原则,当我们增加手机样式时,要同时增加所有品牌的手机,这样增加了代码维护成本
-
解决方案——使用桥接模式
桥接(Bridge)模式——基本介绍
桥接(Bridge)模式是指
-
将实现与抽象放在两个不同的类层次中,使两个层次可以独立改变
-
是一种结构型设计模式
-
Bridge 模式基于类的最小设计原则,通过使用封装、聚合及继承等行为让不同的类承担不同的职责。它的主要特点是把抽象(Abstraction)与行为实现(Implementation)分离开来,从而可以保持各部分的独立性以及应对他们的功能扩展
桥接(Bridge)模式的优点是
-
由于抽象与实现分离,所以扩展能力强
-
其实现细节对客户透明
缺点是
由于聚合关系建立在抽象层,要求开发者针对抽象化进行设计与编程,这增加了系统的理解与设计难度
桥接模式的结构与实现
模式的结构
桥接(Bridge)模式包含以下主要角色
-
抽象化(Abstraction)角色:定义抽象类,并包含一个对实现化对象的引用
-
扩展抽象化(Refined Abstraction)角色:是抽象化角色的子类,实现父类中的业务方法,并通过组合关系调用实现化角色中的业务方法
-
实现化(Implementor)角色:定义实现化角色的接口,供扩展抽象化角色调用
-
具体实现化(Concrete Implementor)角色:给出实现化角色接口的具体实现
结构图如图 1 所示:
模式的实现
1 package bridge; 2 3 public class BridgeTest { 4 public static void main(String[] args) { 5 Implementor imple=new ConcreteImplementorA(); 6 Abstraction abs=new RefinedAbstraction(imple); 7 abs.Operation(); 8 } 9 } 10 11 // 实现化角色 12 interface Implementor { 13 public void OperationImpl(); 14 } 15 16 // 具体实现化角色 17 class ConcreteImplementorA implements Implementor { 18 public void OperationImpl() { 19 System.out.println("具体实现化(Concrete Implementor)角色被访问" ); 20 } 21 } 22 23 // 抽象化角色 24 abstract class Abstraction { 25 protected Implementor imple; 26 protected Abstraction(Implementor imple) { 27 this.imple=imple; 28 } 29 public abstract void Operation(); 30 } 31 32 // 扩展抽象化角色 33 class RefinedAbstraction extends Abstraction { 34 protected RefinedAbstraction(Implementor imple) { 35 super(imple); 36 } 37 38 public void Operation() { 39 System.out.println("扩展抽象化(Refined Abstraction)角色被访问" ); 40 imple.OperationImpl(); 41 } 42 }
程序的运行结果如下:
-
扩展抽象化(Refined Abstraction)角色被访问
-
具体实现化(Concrete Implementor)角色被访问
桥接模式解决手机操作问题
结构图
代码示例
1 // 接口 2 public interface Brand { 3 void open(); 4 void close(); 5 void call(); 6 }
1 package com.atguigu.bridge; 2 3 public class XiaoMi implements Brand { 4 5 @Override 6 public void open() { 7 System.out.println(" 小米手机开机 "); 8 } 9 10 @Override 11 public void close() { 12 System.out.println(" 小米手机关机 "); 13 } 14 15 @Override 16 public void call() { 17 System.out.println(" 小米手机打电话 "); 18 } 19 }
1 package com.atguigu.bridge; 2 3 public class Vivo implements Brand { 4 5 @Override 6 public void open() { 7 System.out.println(" Vivo 手机开机 "); 8 } 9 10 @Override 11 public void close() { 12 System.out.println(" Vivo 手机关机 "); 13 } 14 15 @Override 16 public void call() { 17 System.out.println(" Vivo 手机打电话 "); 18 } 19 }
1 package com.atguigu.bridge; 2 3 public abstract class Phone { 4 // 组合品牌 5 private Brand brand; 6 7 // 构造器 8 public Phone(Brand brand) { 9 super(); 10 this.brand = brand; 11 } 12 13 protected void open() { 14 this.brand.open(); 15 } 16 17 protected void close() { 18 brand.close(); 19 } 20 21 protected void call() { 22 brand.call(); 23 } 24 }
1 package com.atguigu.bridge; 2 3 // 折叠式手机类,继承抽象类Phone 4 public class FoldedPhone extends Phone { 5 // 构造器 6 public FoldedPhone(Brand brand) { 7 super(brand); 8 } 9 10 public void open() { 11 super.open(); 12 System.out.println(" 折叠样式手机 "); 13 } 14 15 public void close() { 16 super.close(); 17 System.out.println(" 折叠样式手机 "); 18 } 19 20 public void call() { 21 super.call(); 22 System.out.println(" 折叠样式手机 "); 23 } 24 }
1 package com.atguigu.bridge; 2 3 public class Client { 4 public static void main(String[] args) { 5 // 获取折叠式手机 (样式 + 品牌 ) 6 Phone phone1 = new FoldedPhone(new XiaoMi()); 7 phone1.open(); 8 phone1.call(); 9 phone1.close(); 10 System.out.println("=============="); 11 12 Phone phone2 = new FoldedPhone(new Vivo()); 13 phone2.open(); 14 phone2.call(); 15 phone2.close(); 16 System.out.println("=============="); 17 18 UpRightPhone phone3 = new UpRightPhone(new XiaoMi()); 19 phone3.open(); 20 phone3.call(); 21 phone3.close(); 22 System.out.println("=============="); 23 24 UpRightPhone phone4 = new UpRightPhone(new Vivo()); 25 phone4.open(); 26 phone4.call(); 27 phone4.close(); 28 } 29 }
桥接模式在 JDBC 的源码剖析
Jdbc 的 Driver 接口,如果从桥接模式来看,Driver 就是一个接口,下面可以有 MySQL 的 Driver,Oracle 的 Driver,这些就可以当做实现接口类
对 jdbc 源码分析的类图
桥接模式的注意事项和细节
-
实现了抽象和实现部分的分离,从而极大的提供了系统的灵活性,让抽象部分和实现部分独立开来,这有助于系统进行分层设计,从而产生更好的结构化系统
-
对于系统的高层部分,只需要知道抽象部分和实现部分的接口就可以了,其它的部分由具体业务来完成
-
桥接模式替代多层继承方案,可以减少子类的个数,降低系统的管理和维护成本
-
桥接模式的引入增加了系统的理解和设计难度,由于聚合关联关系建立在抽象层,要求开发者针对抽象进行设计和编程
-
桥接模式要求正确识别出系统中两个独立变化的维度(抽象、和实现),因此其使用范围有一定的局限性,即需要有这样的应用场景
桥接模式的应用场景
桥接模式通常适用于以下场景
-
当一个类存在两个独立变化的维度,且这两个维度都需要进行扩展时
-
当一个系统不希望使用继承或因为多层次继承导致系统类的个数急剧增加时
-
当一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性时
常见的应用场景
-
JDBC驱动程序
-
银行转账系统——转账分类: 网上转账,柜台转账,AMT 转账;转账用户类型:普通用户,银卡用户,金卡用户..
-
消息管理——消息类型:即时消息,延时消息;消息分类:手机短信,邮件消息,QQ 消息...
桥接模式模式的扩展
在软件开发中,有时桥接(Bridge)模式可与适配器模式联合使用。当桥接(Bridge)模式的实现化角色的接口与现有类的接口不一致时,可以在二者中间定义一个适配器将二者连接起来,其具体结构图如图 5 所示
原文链接:https://blog.csdn.net/qq784515681/article/details/106087730