【设计模式】二十一、外观模式

113 阅读3分钟

这是我参与「掘金日新计划 · 2 月更文挑战」的第 21 天,点击查看活动详情

系列文章|源码

github.com/tyronczt/de…

定义-是什么

外观模式(Facade Pattern)又叫门面模式,提供了一个统一的接口,用来访问子系统中的一群接口。其主要特征是定义了一个高层接口,让子系统更容易使用,属于结构性模式。

门面模式主要包含两种角色:

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

思考-为什么

应用场景

  1. 子系统越来越复杂,增加门面模式提供简单接口。
  2. 构建多层系统结构,利用门面对象作为每层的入口,简化层间调用。

优点

  1. 简化了调用过程,无需深入了解系统,防止给子系统带来风险。
  2. 减少系统依赖,松散耦合。
  3. 更好的划分访问层次,提高了安全性。
  4. 遵循迪米特法则,即最少知道原则。

缺点

  1. 当增加子系统和扩展子系统行为时,可能容易带来未知风险。
  2. 不符合开闭原则。
  3. 某些情况下可能违背单一职责原则。

应用-怎么用

案例:积分兑换

商城系统中,有积分兑换的模块,兑换积分可能涉及到的模块有:①库存校验系统;②积分支付系统;③物流系统;

相关代码

/**
 *  积分礼物
 */
public class PointsGift {
    private String name;

    public PointsGift(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "PointsGift{" +
            "name='" + name + ''' +
            '}';
    }
}

/**
 * 资格校验:积分校验,库存校验
 */
public class QualifyService {
    public boolean isAvailable(PointsGift pointsGift) {
        System.out.println("校验" + pointsGift + " 积分通过,库存通过");
        return true;
    }
}

/**
 * 积分支付服务
 */
public class PointsPaymentService {
    public boolean pay(PointsGift pointsGift) {
        System.out.println(pointsGift + " 支付扣减积分成功");
        return true;
    }
}
/**
 * 物流服务
 */
public class ShippingService {
    public String shipGift(PointsGift pointsGift) {
        // 物流系统对接逻辑
        System.out.println(pointsGift + " 进入物流系统");
        String shippingOrderNo = "6666";
        return shippingOrderNo;
    }
}

三个子系统服务,外部如果要使用,必须知道流程,这个时候就可以封装一个外观服务; 一个积分礼物兑换的服务暴露,这也符合迪米特法则,即最少知道原则;

修改后代码:

/**
 * 外观模式服务
 */
public class GiftExchangeService {
    private QualifyService qualifyService;
    private PointsPaymentService pointsPaymentService;
    private ShippingService shippingService;

    public GiftExchangeService(QualifyService qualifyService, PointsPaymentService pointsPaymentService, ShippingService shippingService) {
        this.qualifyService = qualifyService;
        this.pointsPaymentService = pointsPaymentService;
        this.shippingService = shippingService;
    }

    /**
     * 礼物兑换
     */
    public void giftExchange(PointsGift pointsGift) {
        if (qualifyService.isAvailable(pointsGift)
                && pointsPaymentService.pay(pointsGift)) {
            String shippingOrderNo = shippingService.shipGift(pointsGift);
            System.out.println(pointsGift + " 返回的订单号 " + shippingOrderNo);
        }
    }
}

/**
 * 测试代码
 */
@Test
 public void giftExchange() {
     GiftExchangeService giftExchangeService = new GiftExchangeService(new QualifyService(), new PointsPaymentService(), new ShippingService());
     giftExchangeService.giftExchange(new PointsGift("iphone15"));
 }

=====================
校验PointsGift{name='iphone15'} 积分通过,库存通过
PointsGift{name='iphone15'} 支付扣减积分成功
PointsGift{name='iphone15'} 进入物流系统
PointsGift{name='iphone15'} 返回的订单号 6666
 

源码1:Spring JDBC 模块下的JdbcUtils类

源码2:RequestFacade类

参考

设计模式-门面模式学习之旅 - 掘金

外观模式 | MRCODE-BOOK