1.桥接模式概念
1.1定义
- 桥接模式(Bridge模式):是指将实现与抽象放在两个不同的类层次中,使两个层次可以独立改变。
- 桥接模式,是结构型的设计模式之一。
- 桥接模式是基于类的最小设计原则,通过使用封装,聚合以及继承等行为来让不同的类承担不同的责任。它的主要特点是把抽象(abstraction)与行为实现(implementation)分离开来,从而可以保持各部分的独立性以及应对它们的功能扩展。
1.2模式结构
桥接模式由四部分组成:
-
抽象化(Abstraction)角色:抽象化给出的定义,并保存一个对实现化对象的引用。通常在这个对象中,要维护一个实现部分的对象引用,抽象对象里面的方法,需要调用实现部分的对象来完成。这个对象中的方法,通常都是和具体业务相关的方法。
-
修正抽象化(RefinedAbstraction)角色:扩展抽象化角色,改变和修正父类对抽象化的定义。通常在这些对象中,定义跟实际业务相关的方法,这些方法的实现通常会使用Abstraction中定义的方法,也可能需要调用实现部分的对象来完成。
-
实现化(Implementor)角色:这个角色给出实现化角色的接口,但不给出具体的实现。必须指出的是,这个接口不一定和抽象化角色的接口定义相同,实际上,这两个接口可以非常不一样,实现化角色应当只给出底层操作,而抽象化角色应当只给出基于底层操作的更高一层的操作。简单来说:由Implementor接口提供基本的操作,而Abstraction中定义的是基于这些基本操作的业务方法。
-
具体实现化(ConcreteImplementor)角色:这个角色给出实现化角色接口的具体实现。
可以看到抽象部分的抽象类和实现部分的接口是聚合关系,表示抽象部分持有实现部分的接口,这样抽象部分就可以调用实现部分完成功能了
2.桥接模式实现
应用实例说明:对不同手机类型的不同品牌实现操作编程(比如:开机、关机、上网、打电话等),如下图所示:
2.1传统方案解决手机操作问题
对应的类图:
问题分析:
- 扩展性问题(类爆炸):如果我们再增加手机的样式,就需要增加各个品牌手机的类,同样如果我们增加一个手机品牌,也要在各个手机样式类下增加。
- 违反了单一职责原则,当我们增加手机样式时,要同时增加所有品牌的手机,这样增加了代码维护成本.
- 解决方案-使用桥接模式
2.2桥接模式解决手机操作问题
使用桥接模式改进传统方式,让程序具有搞好的扩展性,利用程序维护
对应的类图:
代码实现:
//接口
public interface Brand {
void open();
void close();
void call();
}
//抽象类
public abstract class Phone {
//手机品牌
private Brand brand;
public Phone(Brand brand){
super();
this.brand=brand;
}
protected void open(){
this.brand.open();
}
protected void close(){
this.brand.close();
}
protected void call(){
this.brand.call();
}
}
//折叠式手机类,继承抽象类Phone
public class FoldedPhone extends Phone {
public FoldedPhone(Brand brand) {
super(brand);
}
@Override
protected void open() {
super.open();
System.out.println("折叠样式手机");
}
@Override
protected void close() {
super.close();
System.out.println("折叠样式手机");
}
@Override
protected void call() {
super.call();
System.out.println("折叠样式手机");
}
}
//直立式手机类,继承抽象类Phone
public class UprightPhone extends Phone {
public UprightPhone(Brand brand) {
super(brand);
}
@Override
protected void open() {
super.open();
System.out.println("直立样式手机");
}
@Override
protected void close() {
super.close();
System.out.println("直立样式手机");
}
@Override
protected void call() {
super.call();
System.out.println("直立样式手机");
}
}
public class Vivo implements Brand {
@Override
public void open() {
System.out.println("Vivo手机开机");
}
@Override
public void close() {
System.out.println("Vivo手机关机");
}
@Override
public void call() {
System.out.println("Vivo手机打电话");
}
}
public class Vivo implements Brand {
@Override
public void open() {
System.out.println("Vivo手机开机");
}
@Override
public void close() {
System.out.println("Vivo手机关机");
}
@Override
public void call() {
System.out.println("Vivo手机打电话");
}
}
public class Client {
public static void main(String[] args) {
//获取折叠手机(样式+品牌)
Phone phone=new FoldedPhone(new Vivo());
phone.open();
phone.call();
phone.call();
}
}
运行结果:
Vivo手机开机
折叠样式手机
Vivo手机打电话
折叠样式手机
Vivo手机打电话
折叠样式手机
3.桥接模式的注意事项和细节
- 实现了抽象和实现部分的分离,从而极大的提供了系统的灵活性,让抽象部分和实现部分独立开来,这有助于系统进行分层设计,从而产生更好的结构化系统。
- 对于系统的高层部分,只需要知道抽象部分和实现部分的接口就可以了,其它的部分由具体业务来完成。
- 桥接模式替代多层继承方案,可以减少子类的个数,降低系统的管理和维护成本。
- 桥接模式的引入增加了系统的理解和设计难度,由于聚合关联关系建立在抽象层,要求开发者针对抽象进行设计和编程
- 桥接模式要求正确识别出系统中两个独立变化的维度,因此其使用范围有一定的局限性,即需要有这样的应用场景
4.优缺点
优点:
- 桥接模式偶尔类似于多继承方案,但是多继承方案违背了类的单一职责原则,复用性比较差,类的个数也非常多,桥接模式是比多继承方案更好的解决方法。极大的减少了子类的个数,从而降低了管理和维护的成本。
- 桥接模式提高了系统的可扩充性,在两个变化维度中任意扩展一个维度,都不需要修改原有系统。符合开闭原则,就像一座桥,可以把两个变化的维度连接起来。
缺点:
- 桥接模式的引入会增加系统的理解与设计难度,由于聚合关联关系建立在抽象层,要求开发者针对抽象进行设计与编程。
- 桥接模式要求正确识别出系统中两个独立变化的维度,因此其使用范围具有一定的局限性。
5.应用场景
- 如果一个系统需要在构建的抽象化角色和具体角色之间增加更多的灵活性,避免在两个层次之间建立静态的继承联系,通过桥接模式可以使它们在抽象层建立一个关联关系。抽象化角色和实现化角色可以以继承的方式独立扩展而互不影响,在程序运行时可以动态将一个抽象化子类的对象和一个实现化子类的对象进行组合,即系统需要对抽象化角色和实现化角色进行动态耦合。
- 一个类存在两个独立变化的维度,且这两个维度都需要进行扩展
- 对于那些不希望使用继承或因为多层次继承导致系统类的个数急剧增加的系统,桥接模式尤为适用。
- 常见的应用场景:
(1)、JDBC驱动程序
(2)、银行转账系统
转账分类: 网上转账,柜台转账,AMT转账
转账用户类型:普通用户,银卡用户,金卡用户…
(3)、消息管理
消息类型:即时消息,延时消息
消息分类:手机短信,邮件消息,QQ消息…
(4)、JWT中的Peer架构