在现实生活中,某些类具有两个或多个维度的变化,如文字分为不同字体和不同颜色,如果用继承方式,m种字体和n种颜色的文字就有mxn种,不但对应的子类很多,而且扩展困难。如果用桥接模式就能很好的解决这些问题;
一. 定义与特点
1. 定义:
-
将两个继承体系使用聚合、组合连接在一起,这就是桥接模式,它是一种结构型设计模式,
-
桥接模式中有两个继承体系,分别称为“抽象” 和 “实现”。将实现与抽象放在两个不同的类层次中,使两个层次可以独立扩展;
-
抽象类中持有实现类的引用,并含有set函数用于给用户设置这个抽象类的实现;
-
当抽象类的对象设置完实现类对象后,用户就可以通过抽象类的对象访问现实类对象中的函数及变量了;
2. 优点
-
实现了抽象部分和实现部分独立分层,这有助于系统进行分层设计(灵活性),从而产生更好的结构化系统;
-
对于系统的高层部分,只需要知道抽象部分和实现部分的接口就可以了,其他的部分由具体业务来完成;
-
桥接模式替代多层继承方案,可以减少子类的个数,降低系统的管理和维护成本;
3. 缺点
-
由于聚合关联关系建立在抽象层,要求开发者针对抽象化进行设计和编程,这增加了系统的理解和设计难度;
-
桥接模式要求能正确识别出系统中两个独立变化的维度,因此其使用范围有一定的局限性,即需要有这样的应用场景;
二. 应用场景
定一个类内部具有两种或多种变化维度时,使用桥接模式可以解耦这些变化的维度,使高层代码架构稳定;
桥接模式通常适用于以下场景:
-
当一个类存在两个独立变化的维度,且这两个维度都需要进行扩展时;
-
当一个系统不希望使用继承或因多层次继承导致系统的个数急剧增加时;
-
当一个系统需要在构件的抽象化角色与具体化角色这间增加更多的灵活性时;
-
常见的应用场景
1> 消息管理:即时消息, 延时消息(抽象层)
2> 消息分类:图片消息,文字消息,语音消息(实现层)
三. 模式结构
将抽象 与 实现 放在不同的类层次中,继承关系改为聚合或组合关系,其实就是 调用 和 被调用关系;聚合(set() 方法参数)组合(构造方法参数) ;
桥接模式角色分析:
1.抽象化角色(Abstraction): 充当桥接类,聚合Implementor接口,此时为调用与被调用关系,维护了实现化接口及其子实现类;
2.扩展抽象化角色(Refind Abstraction): 实现父类中的业务方法,并通过组合关系调用实现化角色中的业务方法;
3.行为实现化角色(Implementor): 定义实现化角色的接口,供扩展抽象化角色调用;
4.具体实现化角色(ConcreteImplementor): 给出实现化角色的具体实现;
四. 模式实现(解决手机操作问题)
现在对不同类型(直立式,折叠式)的不同品牌(ViVO,XiaoMi)的手机,实现操作编程(如:关机、开机、打电话等);
1.传统解决方案结构图
出现类扩展性问题(类爆炸),若我们再增加手机样式(旋转式),就要在样式下增加所有品牌的手机,同样若增加一个手机品牌,也要在各个手机样式类下增加,这违反了 单一职责原则,这样会导致继承体系过于庞大,增加了代码维护成本。
由于对象的继承关系在编译时就定义好了,因此无法在运行时改变子类中从父类继承过来的实现,且子类的实现与父类有紧密的依赖关系,
以至于父类实现中的任何变化必然会导致子类变化的发生,当你需要复用子类时,如果继承下来的实现不适合解决新的问题,
则父类必须重写或被其他更合适的类替换这种依赖关系限制了灵活性,并最终限制复用性。
2. 使用桥接模式解决:
将一个继承体系中的多种类型的类分成单独的继承体系,然后使用聚合/组合将这个两个继承体系连接在一起,这样当需要增加类时,由于新的类属于一个单独的继承体系,因此只需要在某一个继承体系中增加一个子类即可,从而避免了继承体系过于庞大的问题,而这种将一个继承体系分成两个组合/聚合方式连接的继承体系的方式 就称为“合成/聚合复用原则”。此时,如果增加一个类,只需在一个继承体系中增加一个子类即可,无需增加好多类,从而继承体系不会异常庞大;
抽象化角色(Phone) 调用 实现化角色(Brand) 将垂直继承 变为 扁平结构, 中间聚合桥接;
相关代码
public class BridgeClient {
public static void main(String[] args) {
//获取折叠式手机 样式+品牌
Phone xiaomi=new FoldedPhone(new XiaoMi());
xiaomi.open();
xiaomi.close();
xiaomi.call();
//获取直立式手机 样式+品牌
Phone vivo=new UpRightPhone(new ViVo());
vivo.open();
vivo.close();
vivo.call();
}
}
//品牌接口
public interface Brand {
void open();
void close();
void call();
}
//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手机 打电话");
}
}
//XiaoMi 品牌接口实现类
public class XiaoMi implements Brand{
@Override
public void open() {
System.out.println("小米手机开机");
}
@Override
public void close() {
System.out.println("小米手机关机");
}
@Override
public void call() {
System.out.println("小米手机打电话");
}
}
//手机抽象类
public abstract class Phone {
//组合品牌
private final Brand brand;
//构造器传入
public Phone(Brand brand) {
this.brand = brand;
}
protected void open(){
brand.open();
}
protected void close(){
brand.close();
}
protected void call(){
brand.call();
}
}
//折叠手机(具体抽象类) 继承了抽象类 Phone
public class FoldedPhone extends Phone{
public FoldedPhone(Brand brand) {
super(brand);
}
public void open(){
super.open();
System.out.println("折叠样式手机 打开");
}
public void close(){
super.close();
System.out.println("折叠样式手机 关闭");
}
public void call(){
super.call();
System.out.println("折叠样式手机 打电话");
}
}
//直立手机(具体抽象类), 继承了抽象类Phone
public class UpRightPhone extends Phone{
public UpRightPhone(Brand brand) {
super(brand);
}
public void open(){
super.open();
System.out.println("直立样式手机 打开");
}
public void close(){
super.close();
System.out.println("直立样式手机 关闭");
}
public void call(){
super.call();
System.out.println("直立样式手机 打电话");
}
}
程序运行结果:
小米手机开机
折叠样式手机 打开
小米手机关机
折叠样式手机 关闭
小米手机打电话
折叠样式手机 打电话
ViVo手机 开机
直立样式手机 打开
ViVo手机 关机
直立样式手机 关闭
ViVo手机 打电话
直立样式手机 打电话