外观模式就是提供一个统一的接口供外界调用,以降低内部逻辑复杂性。
如上图,还是拿目前最常用的模式来说,这个SmsServiceImpl里面在发送短信时,调用了一大堆其他内部逻辑。
要记录日志,要插入表数据,要调用外部接口发邮件等等。
如果要每次send(Sms)后都需要自己手动调用一次 LogService,DBService等里面的方法执行逻辑,我想谁都不愿意。
那么此处提供一个统一的接口,这个接口给controller调用,controller并不知道SmsService内部做了什么逻辑,他只需要知道调用这个SmsService.send()方法能够发送短信就行。
那么此处是不是算应用了外观模式呢?
定义一个SmsService,里面在send短信时,还调用了其他的内部逻辑。
/**
* @author lw
* @date 2022/3/29 0029
* @description 短信服务
*/
public class SmsService {
private DBService dbService = new DBService();
private LogService logService = new LogService();
private MailService mailService = new MailService();
public void send(String toPhone, String content) {
System.out.println("SmsService :" + content);
//特殊号码发短信
if("12306".equals(toPhone)){
this.mailService.send(content);
}
dbService.writeDb();
logService.log();
}
}
调用者
SmsService smsService = new SmsService();
smsService.send("12306","hello world");
这确实看起来是外观模式,提供了一个统一的接口给外部,降低了内部逻辑复杂性。
调用者只需要调用一个send方法即可。
但是别忘了另一个原则,低耦合和单一原则。
发送短信的方法里面还记录日志和数据库,还发送邮件,这像话么?
在移动CRM项目中,有一个一万多行的短信发送类,里面是各种 if-else 的判断业务,这些业务是用来判断是否发送短信的。
而真正发送短信的代码。提取出来只有几行,就是往短信表里面插入一行数据。
但如果让一个调用者如下面这么写代码,那岂不是在项目里面写的很烦,既要考虑发短信,还要判断是否记录日志和发邮件等等。万一以后变了呢?
所有设计都是为了以后易于扩展和变更,毕竟甲方的想法是很天马行空的。
String toPhone = "12306";
String content = "hello world";
SmsService smsService = new SmsService();
smsService.send(toPhone,content);
DBService dbService = new DBService();
LogService logService = new LogService();
MailService mailService = new MailService();
//特殊号码发短信
if("12306".equals(toPhone)){
mailService.send(content);
}
dbService.writeDb();
logService.log();
当解决不了时,没有什么是包一层解决不了的。
/**
* @author lw
* @date 2022/3/30 0030
* @description 消息发送
*/
public class SenderService {
private DBService dbService = new DBService();
private LogService logService = new LogService();
private MailService mailService = new MailService();
private SmsService smsService = new SmsService();
public void send(String toPhone,String content){
this.smsService.send(toPhone,content);
//特殊号码发短信
if("12306".equals(toPhone)){
this.mailService.send(content);
}
dbService.writeDb();
logService.log();
}
}
/**
* @author lw
* @date 2022/3/29 0029
* @description 短信服务
*/
public class SmsService {
public void send(String toPhone, String content) {
System.out.println("SmsService :" + content);
}
}
String toPhone = "12306";
String content = "hello world";
SenderService senderService = new SenderService();
senderService.send(toPhone,content);
这样调用者就可以使用SenderService来发送消息,同时调用者也可以直接使用SmsService.send方法来仅仅发送短信。
外观模式并不妨碍调用者对子系统或者方法的访问。
总结
外观模式,从外面看起来光鲜,哪管你金玉其外败絮其中,只要我调用你的方法调的方便即可。