设计模式之外观模式

时光毁灭记忆、已成空白 提交于 2020-03-05 23:18:42

定义

又叫门面模式,提供了一个统一的接口,用来访问子系统中的一群接口。

外观模式定义了一个高层接口,让子系统更容易使用。

类型

结构型

适用场景

①、子系统越来越复杂,增加外观模式提供简单调用接口。
②、构建多层系统结构,利用外观对象作为每层的入口,简化层间调用。

优缺点

优点:
①、简化了调用过程,无需了解深入子系统,防止带来风险。
②、减少系统依赖、松散耦合。
③、更好的划分访问层次。
④、符合迪米特法则,即最少知道原则。

缺点:
①、增加子系统、扩展子系统行为容易引入风险。
②、不符合开闭原则。

代码实现

案例:用户需要在支付宝的会员中心,通过支付积分兑换商品,则兑换流程大致是:校验商品库存–>积分校验–>积分支付–>生成物流。上面四个流程可以分别看做子系统,将这四个流程的逻辑封装为一个商品兑换的外观类。
首先创建一个商品类:

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的简单的日志门面

参考链接
https://coding.imooc.com/learn/list/270.html

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!