设计模式之门面模式详解

设计模式之门面模式详解

文章目录

  • 设计模式之门面模式详解
    • 一、什么是门面模式
    • 二、门面模式的应用场景
    • 三、门面模式的角色组成
    • 四、门面模式通用写法
    • 五、门面模式在业务中的应用
    • 六、门面模式优缺点

一、什么是门面模式

门面模式(Facade Pattern) 又叫外观模式,提供了一个统一的接口,用来访问子系统中的一群接口 。其主要特征是定义了一个高层接口,让子系统更容易使用,属于结构型模式。在我们日常编码中也在无意中大量的使用着门面模式,例如ServiceA中调用其他多个Service的方法,然后再将ServiceA的方法暴露给Controller调用,ServiceA就相当于一个门面使得Controller能够间接的调用其他Service子系统,这也就是门面模式的一种应用。

二、门面模式的应用场景

  • 子系统越来越复杂,增加门面模式提供简单接口

  • 构建多层系统结构,利用门面对象作为每层的入口,简化层间调用

三、门面模式的角色组成

门面模式的通用类图:
设计模式之门面模式详解_第1张图片

  • 外观角色(Facade): 也称门面角色,系统对外的统一接口;
  • 子系统角色(SubSystem): 可以同时有一个或多个SubSystem。每个SubSystem都不是一个单独的类,而是一个类的集合。SubSystem并不知道Facade 的存在,对于SubSystem而言,Facade只是另外一个客户端而已(即Facade对SubSystem是透明的)。

四、门面模式通用写法

我们先分别创建3个子系统的业务逻辑SubSystemASubSystemBSubSystemC

/**
 * 子系统角色 - SubSystemA
 *
 * @author zdp
 * @date 2022/9/3 14:38
 */
public class SubSystemA {

    public void doA() {
        System.out.println("doing A stuff");
    }

}
/**
 * 子系统角色 - SubSystemB
 *
 * @author zdp
 * @date 2022/9/3 14:38
 */
public class SubSystemB {

    public void doB() {
        System.out.println("doing B stuff");
    }

}
/**
 * 子系统角色 - SubSystemC
 *
 * @author zdp
 * @date 2022/9/3 14:38
 */
public class SubSystemC {

    public void doC() {
        System.out.println("doing C stuff");
    }

}

紧接着再创建一个外观角色类Facade :

/**
 * 外观角色 Facade 相当于注入其他Service,封装其方法暴露给客户端
 *
 * @author zdp
 * @date 2022/9/3 14:34
 */
public class Facade {

    //相当于@Autowire注入
    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();
    }
}

编写测试类

/**
 * facade 通用写法
 *
 * @author zdp
 * @date 2022/9/3 14:36
 */
class Test {
    // 客户 (相当于Controller)
    public static void main(String[] args) {
        Facade facade = new Facade();
        facade.doA();
        facade.doB();
        facade.doC();
    }
}

五、门面模式在业务中的应用

需求:现有积分、支付、库存、物流系统,需要做一个积分兑换商城

  1. 创建商品类
   /**
    * 商品详情信息
    *
    * @author zdp
    * @date 2022/9/3 14:52
    */
   @Data
   @Builder
   public class GoodsInfo {
       private String name;
       private Integer integral;
       private BigDecimal price;
   }
  1. 积分系统
   /**
    * 积分系统
    *
    * @author zdp
    * @date 2022/9/3 14:51
    */
   @Slf4j
   public class IntegralSystem {
   
       /**
        * 扣减积分
        *
        * @param  info GoodsInfo
        * @author zdp
        * @date   2022/9/3 15:10
        * @return result
        */
       public boolean deductIntegral(GoodsInfo info){
           log.info("商品【{}】扣减积分成功", info.getName());
           return true;
       }
   }
  1. 库存系统
/**
  * 库存系统
  *
  * @author zdp
  * @date 2022/9/3 14:54
  */
 @Slf4j
 public class StockSystem {
 
     public static int goodsStock = 2;
 
     /**
      * 扣减库存
      *
      * @param  info GoodsInfo
      * @author zdp
      * @date   2022/9/3 15:07
      * @return result
      */
     public boolean deductStock(GoodsInfo info){
         goodsStock -= 1;
         if (goodsStock < 0) {
             log.info("商品【{}】扣减库存失败,库存不足~", info.getName());
             return false;
         }
         log.info("商品【{}】扣减库存成功~", info.getName());
         return true;
     }
 }
  1. 支付系统
/**
  * 支付系统
  *
  * @author zdp
  * @date 2022/9/3 14:52
  */
 @Slf4j
 public class PaymentSystem {
 
     StockSystem stock = new StockSystem();
     IntegralSystem integral = new IntegralSystem();
     /**
      * 付款
      *
      * @param  info GoodsInfo
      * @author zdp
      * @date   2022/9/3 15:08
      * @return result
      */
     public boolean pay(GoodsInfo info){
         if (stock.deductStock(info)) {
             integral.deductIntegral(info);
             log.info("商品【{}】支付成功,准备发货~", info.getName());
             return true;
         }
         return false;
     }
 }
  1. 物流系统
/**
 * 物流系统
 *
 * @author zdp
 * @date 2022/9/3 14:49
 */
@Slf4j
public class LogisticsSystem {

    /**
     * 对接物流系统,商品发货
     *
     * @param  info goods info
     * @author zdp
     * @date   2022/9/3 14:57
     * @return java.lang.String 物流单号
     */
    public void deliverGoods(GoodsInfo info){
        //对接物流系统...
        log.info("商品【{}】,进入物流系统,单号: {}", info.getName(), new Date().getTime());
    }
}
  1. 外观角色门面
/**
  * 外观角色 Facade 商品兑换门面 整合了支付和物流系统,使得前端开发逻辑处理简单,不用再调用多个系统
  *
  * @author zdp
  * @date 2022/9/3 15:15
  */
 public class GoodsFacadeSystem {
 
     PaymentSystem payment = new PaymentSystem();
     LogisticsSystem logistics = new LogisticsSystem();
 
     /**
      * 商品兑换
      *
      * @param  info GoodsInfo
      * @author zdp
      * @date   2022/9/3 15:16
      * @return 商品兑换结果
      */
     public boolean exchange(GoodsInfo info){
         if (!payment.pay(info)) {
             return false;
         }
         logistics.deliverGoods(info);
         return true;
     }
 }
  1. 测试
 public class Test {
 
     public static void main(String[] args) throws Exception{
         GoodsFacadeSystem facade = new GoodsFacadeSystem();
         for (int i = 0; i < 3; i++) {
             GoodsInfo info = GoodsInfo.builder()
                     .name("拖孩儿")
                     .integral(100)
                     .price(new BigDecimal("10.05"))
                     .build();
             facade.exchange(info);
             TimeUnit.MILLISECONDS.sleep(1);
         }
     }
 
 }

设计模式之门面模式详解_第2张图片

六、门面模式优缺点

  • 优点
    • 简化了调用过程,无需深入了解子系统,以防给子系统带来风险
    • 减少系统依赖,松散耦合
    • 更好地划分访问层次,提高了安全性
    • 遵循迪米特法则,即最少知道原则
  • 缺点
    • 当增加子系统和扩展子系统行为时,可能容易带来风险
    • 不符合开闭原则
    • 某些情况下可能违背单一职责原则

你可能感兴趣的:(设计模式,设计模式,java)