设计模式之门面模式
门面模式:
门面模式(Facade Pattern) 又叫外观模式, 提供了一个统一的接口, 用来访问子系统中的一群接口。其主要特征是定义了一个高层接口,让子系统更容易使用,属于结构性模式。
要求一个子系统的外部与其内部的通信必须通过一个统一的对象进行。门面模式提供一个高层次的接口,使得子系统更易于使用。其实,在我们日常的编码工作中,我们都在有意无意地大量使用门面模式,但凡只要高层模块需要调度多个子系统(2个以上类对象),我们都会自觉地创建一个新类封装这些子系统,提供精简接口,让高层模块可以更加容易间接调用这些子系统的功能。尤其是现阶段各种第三方SDK, 各种开源类库,很大概率都会使用门面模式。尤其是你觉得调用越方便的,门面模式使用的一般更多。
门面模式的应用场景:
- 子系统越来越复杂,增加门面模式提供简单接口
- 构建多层系统结构,利用门面对象作为每层的入口,简化层间调用。
门面模式主要包含2种角色:
- 外观角色(Facade) :也称门面角色, 系统对外的统一接口;
- 子系统角色(SubSystem),可以同时有一个或者多个SubSystem,每个SubSystem都不是一个单独的类, 而是一个类的集合。SubSystem并不知道Facade的存在, 对于SubSystem而言, Facade只是另一个客户端而已(即Facade对SubSystem透明) 。
门面模式业务场景实例:
就以积分兑换礼品为例, 在礼品商城中的大部分功能并不是全部重新开发的, 而是要去对接已有的各个子系统。这些子系统可能涉及到积分系统、支付系统、物流系统的接口调用。如果所有的接口调用全部由前端发送网络请求去调用现有接口的话,一则会增加前端开发人员的难度,二则会增加一些网络请求影响页面性能。这个时候就可以发挥门面模式的优势了。将所有现成的接口全部整合到一个类中,由后端提供统一的接口给前端调用,这样前端开发人员就不需要关心各接口的业务关系,只需要把精力集中在页面交互上。下面我们用代码来模拟一下这个场景。首先, 创建礼品的实体类GiftInfo:
public class GiftInfo {
private String name;
public GiftInfo(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
然后编写各个子系统的逻辑业务代码:
//校验
public class QualifyService {
public boolean isAvailable(GiftInfo giftInfo) {
System.out.println("校验" + giftInfo.getName() + "积分通过,库存通过。");
return true;
}
}
//支付
public class PaymentService {
public boolean pay(GiftInfo giftInfo) {
System.out.println("扣减" + giftInfo.getName() + " 积分成功");
return true;
}
}
//物流
public class ShippingService {
public String delivery(GiftInfo giftInfo) {
System.out.println(giftInfo.getName() + "进入物流系统");
String shippingNo = "666";
return shippingNo;
}
}
门面:
public class FacadeService {
private QualifyService qualifyService = new QualifyService();
private PaymentService paymentService = new PaymentService();
private ShippingService shippingService = new ShippingService();
public void exchange(GiftInfo giftInfo){
if(qualifyService.isAvailable(giftInfo)){
if(paymentService.pay(giftInfo)){
String shippingNo = shippingService.delivery(giftInfo);
System.out.println("物流系统下单成功,物流单号是:" + shippingNo);
}
}
}
}
测试:
public class Test {
public static void main(String[] args) {
FacadeService facadeService = new FacadeService();
GiftInfo giftInfo = new GiftInfo("《Spring 5核心原理》");
facadeService.exchange(giftInfo);
}
}
优点:
- 简化了调用过程,无需深入了解子系统,以防给子系统带来风险。
- 减少系统依赖、松散耦合
- 更好地划分访问层次,提高了安全性
- 遵循迪米特法则,即最少知道原则。
缺点:
- 当增加子系统和扩展子系统行为时,可能容易带来未知风险
- 不符合开闭原则