设计模式之桥接模式
将抽象部分与它的实现部分分离,使它们都可以独立地变化。
就说一个场景,如下图所示,有SmsService和MailService两个服务,分别负责发短信和发邮件。
同时有三个日志服务,负责记录日志等。
在发送短信或者邮件后,需要记录日志,那么此时需要记录DB,File,Server三种日志,而后续还有很多日志服务要接入进来。
甚至后面不仅仅是sms和mail两种消息服务,还有其他消息服务过来。
问,如何快速适应变化,能在无论增加消息服务还是日志服务后能快速扩展,而不用写太多代码。
/**
* @author lw
* @date 2022/3/29 0029
* @description 短信服务
*/
public class SmsService {
private DBLogService dbLogService = new DBLogService();
private FileLogService fileLogService = new FileLogService();
private ServerLogService serverLogService = new ServerLogService();
public void send(String toPhone, String content) {
System.out.println("SmsService :" + content);
dbLogService.log();
fileLogService.log();
serverLogService.log();
}
}
如果使用上述代码,那么需要在SmsService和MailService两个类里面加上三个类,同时还需要分别调用。
后续每增加一个日志服务,就需要改一遍代码,十几个消息服务,就要改十几个类。
当然上述可以使用工厂模式解决,由工厂封装对应的SmsService,从而将日志服务封装到Service中去。
用桥接模式呢?从定义可以知道,需要有两个部分,抽象部分和实现部分,两者都可以独立变化。
首先就要考虑出抽象的部分,很明显就是三个日志类抽象出来(LogService),两个消息服务类抽象出来(SenderService)。
/**
* @author lw
* @date 2022/3/29 0029
* @description 消息服务
*/
public abstract class AbstractSenderService implements SenderService {
List<LogService> logServices = new ArrayList<>();
public AbstractSenderService(LogService ...logServices){
for (LogService logService : logServices) {
this.logServices.add(logService);
}
}
@Override
public abstract void send(Map param);
}
将消息类抽象出来,抽象成接口和类,抽象类里面设置需要记录日志的日志服务。
将日志服务也抽象出一个接口。
调用者
DBLogService dbLogService = new DBLogService();
FileLogService fileLogService = new FileLogService();
ServerLogService serverLogService = new ServerLogService();
SenderService senderService = new SmsService(dbLogService,fileLogService,serverLogService);
senderService.send(null);
如果每次new对象出来,都需要加入这一大堆消息服务的话,那还不如直接写在SmsService中呢。
不过可以继续加一层工厂,用来产生SenderService。
包一层不行的话,那就包两层。
总结
桥接模式,将两个不同的类关联起来。
需要实现两个部分,抽象部分和实现部分。