门面模式

# 门面模式 门面模式又叫做外观模式,提供统一的一个接口,用来访问子系统中的一群接口; 门面模式定义了一个高层接口,让子系统更容易使用; 门面模式属于结构型模式; ## 类图 ![](https://oscimg.oschina.net/oscnet/up-937cef58fcd4540a37854b0eeb31cda5c06.png) ### Facade 门面类 ```text public class Facade { // 继承各个子系统功能,进行封装,一定程度上不遵循单一职责原则 SubSystemA subSystemA = new SubSystemA(); SubSystemB subSystemB = new SubSystemB(); SubSystemC subSystemC = new SubSystemC(); public void doA(){ subSystemA.doA(); } public void doB(){ subSystemB.doB(); } public void doC(){ subSystemC.doC(); } } ``` ### 子系统A ```text public class SubSystemA { public void doA(){} } ``` ### 子系统B ```text public class SubSystemB { public void doB(){} } ``` ### 子系统C ```text public class SubSystemC { public void doC(){} } ``` 以上Facade类集成了三个子系统的类,在自己定义的方法中,并不是Facade自己实现的逻辑,而是 调用了对应子系统的方法,这种实现方式叫做门面模式;是不是很简单; 看到这是不是有点似曾相识呢,没错,我们天天都在写的Controller,Service,Dao不就是门面模式吗, 没错,只不过把这种方式形成方法论,也就有了所谓的门面模式! ## 举个栗子 > 一些商业博客会有一个功能,就是发表文章或者评论点赞会获得一些积分啊,虚拟币啊,然后会有积分商城, > 在里面可以免费的兑换商品,其实很难凑的够积分,不够费劲的... 好了,结合伪代码来体验门面模式👇👇👇: **下面是一些演示所需要的类:** ### 关系图如下 ![](https://oscimg.oschina.net/oscnet/up-e117a07cbd9489e5a037d1e64961c1062c7.png) ### PaymentService 支付服务 ```text public class PaymentService { public boolean pay(GiftInfo giftInfo){ System.out.println("扣减" + giftInfo.getName() + "积分成功!"); return true; } } ``` ### QualityService 库存服务 ```text public class QualityService { public boolean isAvailable(GiftInfo giftInfo){ System.out.println("校验" + giftInfo.getName() + "积分通过,库存充足!"); return true; } } ``` ### ShipService 物流服务 ```text public class ShipService { public String doShip(GiftInfo giftInfo){ System.out.println(giftInfo.getName() + "生成物流订单"); return String.valueOf(System.currentTimeMillis()); } } ``` ### 客户端 非门面模式写法 ```text public static void main(String[] args) { QualityService qualityService = new QualityService(); PaymentService paymentService = new PaymentService(); ShipService shipService = new ShipService(); GiftInfo giftInfo = new GiftInfo(" 《Java编程思想》 "); if (!qualityService.isAvailable(giftInfo)){ System.err.println("Quality not enough!"); } if (!paymentService.pay(giftInfo)){ System.err.println("Pay error!"); } String shipNo = shipService.doShip(giftInfo); System.err.println("Order shipNo:" + shipNo); } ``` > 这种写法会将库存,支付和物流等服务都暴露给调用方,是很不安全的,而且造成客户端依赖严重,代码臃肿; ### 门面模式写法 ```text public static void main(String[] args) { FacadeService facadeService = new FacadeService(); GiftInfo giftInfo = new GiftInfo(" 《Java编程思想》 "); String shipNo = facadeService.doOrder(giftInfo); System.err.println("Order shipNo:" + shipNo); } ``` > 上面这种就是门面模式的写法👆 , 相信大家应该很熟悉吧,这样的话,暴露给客户端就一个订单服务就可以了! ## 门面模式的应用场景 - **子系统越来越复杂,增加门面模式提供简单的接口,给用户使用;** - **构建多层的系统接口,利用门面对象作为每层的入口,简化层之间的调用** ## 门面模式的应用 Spring JdbcUtils Mybatis configuration Tomcat requestFacade responseFacade ## 门面模式的优点 - **简化了调用过程,无需深入了解子系统,以防止给子系统带来风险** > 根据上面礼品兑换的逻辑,用户根本不care你底层的兑换逻辑,什么库存啊,支付状态啊,生成订单逻辑等等,对于用户来说,我只需要一步下单即可; - **减少系统依赖,松耦合** > 这一点也是相对客户端来说,客户端只关心的的订单服务就好了,其他的库存,供应链等都不关系; - **更好的划分访问层次,提高了安全性** > 合理的划分层次,减少底层系统的暴露,仅仅暴露一些必要的状态和接口,这一点大家应该都知道的,像service层调用Dao层,而不能在service层直接访问 > 数据库; - **遵循迪米特法则** ## 门面模式的缺点 - **当子系统的功能需要扩展或者修改的时候,上层封装可能要面临修改的风险,这样增加了后期的维护成本,也不遵循开闭原则** - **可能会违背单一职责原则** ## 门面模式和代理模式的区别 简单来说,门面模式就是一种代理模式,是属于静态代理的模式;但是和静态代理又有一些区别,门面模式的侧重点在于对底层的封装,而静态代理则 则终于对代理对象的增强,除了调用受委托对象的方法之外,可以扩展额外的功能; 很多时候会把门面模式注入成单例,比如一些全局的Util,还有我们常见的一些Controller等等;