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