16 桥接模式
-
将抽象部分与它的实现部分分离,使它们都可以独立地变化
-
理解
-
抽象:指我们通常可以将现实中的事物(消息)抽象成类,不是指抽象类
-
实现:指方法的具体实现
-
抽象的变化:我们通过继承来表示抽象的变化,例如信息这个抽象,可以衍生出普通消息、加急消息和特急消息,他们的本质还是消息,只不过可能属性不同,他们都需要继承消息类
-
实现的变化:最开始时候,如果我们想改变该类中的某个方法的具体实现,也是通过用一个新类继承该类,并重写这个方法。例如想增加使用邮件发送消息和使用电话发送消息这两种实现,需要新增这两个类继承消息类,但这样就会导致每需要一个新的方法实现,就需要创建一个新的类
-
因此如果按原来这种方式,抽象如果有n种变化,实现有m种变化,最终就会导致需要创建m*n个类
-
因此将抽象部分与它的实现部分分离,将类中方法的实现转交给一个实现对象,由该实现对象完成具体实现,这样就完成了分离,此时当再需要改变实现时,就不需要重新创建一个子类了,而是直接修改具体的实现对象即可
-
强关联:在编译期就已经确定的,无法在运行时动态改变的关联,继承是强关联,聚合是弱关联
-
其实面向接口编程也可以看成是一种桥接,Client就是抽象部分,通过使用接口,来和该接口的具体实现解耦
-
本质:分离抽象和实现
-
优点
- 抽象和实现可以独立变化
- 系统高层部分只需知道抽象部分和实现部分的接口即可
- 可以动态切换实现
- 减少子类的个数
-
使用场景
- 程序运行期间需要动态切换实现
- 抽象和实现需要独立变化
- 采用继承的实现方案,会产生很多子类时,可以考虑采用桥接模式,分析功能变化的原因,看看是否能分离成不同的纬度,然后通过桥接模式来分离它们,从而减少子类的数目
-
类图
16.1 代码
- 将消息分为两个维度
- 消息类型
- 普通
- 加急
- 特急
- 消息发送方式
- 系统内
- 手机
- 邮件
- 消息类型
- AbstractMessage:Abstraction
public abstract class AbstractMessage {
//持有一个实现部分的引用
protected MessageImplementor impl;
//默认构造方法
public AbstractMessage(MessageImplementor impl){
this.impl = impl;
}
//operation,send为OperationImpl
public void sendMessage(String message,String toUser){
this.impl.send(message, toUser);
}
}
- CommonMessage:普通消息、RefinedAbstraction
public class CommonMessage extends AbstractMessage{
public CommonMessage(MessageImplementor impl) {
super(impl);
}
//普通消息,所以要拼接发送的消息字符串时,加上"普通"两个字
@Override
public void sendMessage(String message, String toUser) {
message = "*普通*:" + message;
super.sendMessage(message, toUser);
}
}
- UrgencyMessage:紧急消息
public class UrgencyMessage extends AbstractMessage{
public UrgencyMessage(MessageImplementor impl) {
super(impl);
}
public void sendMessage(String message, String toUser) {
message = "*加急*:" + message;
super.sendMessage(message, toUser);
}
}
- VeryUrgencyMessage
public class VeryUrgencyMessage extends AbstractMessage{
public VeryUrgencyMessage(MessageImplementor impl) {
super(impl);
}
public void sendMessage(String message, String toUser) {
message = "*特急*:" + message;
super.sendMessage(message, toUser);
}
//扩展自己的新功能:特急任务,需要催促接收人尽快完成,messageId:消息编号
public void urge(String messageId) {
//发出催促的信息 ,比如:每隔半小时 发送一条催促消息
//TODO 逻辑
}
}
- MessageImplementor:Implementor
public interface MessageImplementor {
//发送消息,message 消息内容,toUser 接收人
public void send(String message,String users);
}
- SystemMessage:ConcreteImplementorA
public class SystemMessage implements MessageImplementor {
@Override
public void send(String message, String users) {
System.out.println("使用站內消息方式,发送信息【"+message+"】To【"+users+"】");
}
}
- MobileMessage
public class MobileMessage implements MessageImplementor {
@Override
public void send(String message, String users) {
System.out.println("使用短信方式,发送信息【"+message+"】To【"+users+"】");
}
}
- EmailMessage
public class EmailMessage implements MessageImplementor {
@Override
public void send(String message, String users) {
System.out.println("使用邮件方式,发送信息【"+message+"】To【"+users+"】");
}
}
- Client
public class Client {
public static void main(String[] args) {
MessageImplementor impl = new EmailMessage();
AbstractMessage m = new CommonMessage(impl);
m.sendMessage("123", "hdd");
m = new UrgencyMessage(impl);
m.sendMessage("123", "hdd");
m = new VeryUrgencyMessage(impl);
m.sendMessage("123", "hdd");
//具体实现变化后,整个功能随之变化,改变为使用手机发送短信
impl = new MobileMessage();
m = new CommonMessage(impl);
m.sendMessage("123", "hdd");
m = new UrgencyMessage(impl);
m.sendMessage("123", "hdd");
m = new VeryUrgencyMessage(impl);
m.sendMessage("123", "hdd");
}
}