门面模式
# 门面模式
门面模式又叫做外观模式,提供统一的一个接口,用来访问子系统中的一群接口;
门面模式定义了一个高层接口,让子系统更容易使用;
门面模式属于结构型模式;
## 类图

### 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不就是门面模式吗,
没错,只不过把这种方式形成方法论,也就有了所谓的门面模式!
## 举个栗子
> 一些商业博客会有一个功能,就是发表文章或者评论点赞会获得一些积分啊,虚拟币啊,然后会有积分商城,
> 在里面可以免费的兑换商品,其实很难凑的够积分,不够费劲的... 好了,结合伪代码来体验门面模式👇👇👇:
**下面是一些演示所需要的类:**
### 关系图如下

### 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等等;