定义
又叫门面模式,提供了一个统一的接口,用来访问子系统中的一群接口。
外观模式定义了一个高层接口,让子系统更容易使用。
类型
结构型
适用场景
①、子系统越来越复杂,增加外观模式提供简单调用接口。
②、构建多层系统结构,利用外观对象作为每层的入口,简化层间调用。
优缺点
优点:
①、简化了调用过程,无需了解深入子系统,防止带来风险。
②、减少系统依赖、松散耦合。
③、更好的划分访问层次。
④、符合迪米特法则,即最少知道原则。
缺点:
①、增加子系统、扩展子系统行为容易引入风险。
②、不符合开闭原则。
代码实现
案例:用户需要在支付宝的会员中心,通过支付积分兑换商品,则兑换流程大致是:校验商品库存–>积分校验–>积分支付–>生成物流。上面四个流程可以分别看做子系统,将这四个流程的逻辑封装为一个商品兑换的外观类。
首先创建一个商品类:
public class Product {
private String name;
public Product(String name){
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
这里只记录了商品的name属性,接着创建一个校验库存的子系统。
public class StockService {
/**
* 校验库存
*/
public boolean hasRemain(Product product) {
System.out.println("校验" + product.getName() + "的存量");
return true;
}
}
接着需要校验商品积分
public class IntegralService {
/**
* 校验积分
*/
public boolean hasEnough(Product product) {
System.out.println("校验" + product.getName() + "的积分");
return true;
}
}
积分校验完成,需要进行支付,创建积分支付的子系统。
public class PayService {
/**
* 积分支付
*/
public boolean hasPay(Product product) {
System.out.println(product.getName() + "积分支付成功");
return true;
}
}
支付完,就会生成物流了,这里以返回物流号为例。
public class LogisticsService {
/**
* 生成物流信息
*/
public String createNumber(Product product) {
String num = UUID.randomUUID().toString();
System.out.println(product.getName() + "已生成物流信息");
return num;
}
}
这里如果不使用外观模式将四个子系统的逻辑进行封装,在应用层对接时,上面四个子系统都是需要关注的,要挨个进行交互,并且是需要有顺序的交互。不然,商品就会兑换失败。这显然对用户来说是不友好的。用户只用关心商品兑换的逻辑。至于是怎么兑换的,用户是不需要知道的。此时,就需要将上述的各个逻辑封装为一个商品兑换的外观类。
/**
* @ClassName: ProductExchange
* @Author: 清风一阵吹我心
* @Description: TODO 没有集成spring框架,只能通过setter的注入方式
* @Date: 2020/3/3 17:40
* @Version 1.0
**/
public class ProductExchange {
private StockService stockService;
private IntegralService integralService;
private PayService payService;
private LogisticsService logisticsService;
public void setStockService(StockService stockService) {
this.stockService = stockService;
}
public void setIntegralService(IntegralService integralService) {
this.integralService = integralService;
}
public void setPayService(PayService payService) {
this.payService = payService;
}
public void setLogisticsService(LogisticsService logisticsService) {
this.logisticsService = logisticsService;
}
public void productExchange(Product product) {
// 校验库存
if (stockService.hasRemain(product)) {
// 校验积分
if (integralService.hasEnough(product)) {
// 积分支付是否成功
if (payService.hasPay(product)) {
// 返回物流订单号
String number = logisticsService.createNumber(product);
System.out.println("物流订单号是:" + number);
}
}
}
}
}
最后通过编写测试类进行测试。
public class MainTest {
public static void main(String[] args) {
Product product = new Product("机械键盘");
ProductExchange productExchange = new ProductExchange();
// 没有使用spring,只能使用new来创建
productExchange.setStockService(new StockService());
productExchange.setIntegralService(new IntegralService());
productExchange.setPayService(new PayService());
productExchange.setLogisticsService(new LogisticsService());
// 兑换商品
productExchange.productExchange(product);
}
}
输出结果:
C:\android\java\jdk1.8\bin\java.exe
校验机械键盘的存量
校验机械键盘所需要的积分
机械键盘积分支付成功
机械键盘已生成物流信息
物流订单号是:4f4c04f0-6159-48fa-9fd0-52ffc6c1f91b
如果使用IDEA开发工具,可以直接看UML用例图,测试类和子系统之间是“create”的关系,说明应用层依赖了子系统,这是因为上面的代码没有使用spring框架,在应用层使用了new关键字,创建了子系统的对象。如果直接在外观类中默认生成子系统的对象。这样就不会存在应用层依赖子系统的情况了。这一点其实是无关紧要的。
相关源码
1. spring-jdbc中的JdbcUtils
2. mybatis中的configuration
3. tomcat中的RequestFacade、ResponseFacade等等
4. SLF4J是Java的简单的日志门面
来源:CSDN
作者:清风一阵吹我心
链接:https://blog.csdn.net/qq_32101993/article/details/104674947