# 外观模式Facade

loading

# 一、概念

# 1、定义

又叫门面模式,提供了一个统一的接口,用来访问子系统中的一群接口,外观模式定义了一个高层接口,让子系统更容易使用。

# 2、类型

结构型

# 3、适用场景

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

# 4、优点

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

# 5、缺点

  • 增加子系统、扩展子系统行为容易引入风险
  • 不符合开闭原则

# 6、相关设计模式

  • 外观模式和中介者模式

外观模式关注的是外接和子系统之间的交互;中介者模式关注的是子系统内部之间的交互

  • 外观模式和单例模式

通常可以把外观模式的外观对象做成单例模式

  • 外观模式和抽象工厂模式

外观类可以通过抽象工厂获取子系统的实例,子系统可以将内部对外观类屏蔽

# 二、Coding

各大商城的会员一般都会有积分吧,而且一定的积分是可以兑换商品的,我们想想看,用积分兑换礼品的时候后台都需要哪些逻辑操作呢?

  1. 检测当前积分是否足够以及礼品的库存是否足够的校验系统
  2. 进行积分支付的积分支付系统
  3. 物流运输配送的物流配送系统

那么我们这就需要封装一个礼品兑换的类,然后内部融合这3个子系统。

首先创建一个礼品类:

public class Gift {

    private String name;

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

接下来是上述的3个子系统,先是校验系统:

public class QualifyService {

    public boolean isAvailable(Gift gift) {
        // 具体逻辑
        System.out.println("校验【" + gift.getName() + "】积分资格通过,库存通过");
        return true;
    }
}
1
2
3
4
5
6
7
8

这里假设直接校验通过。

积分支付系统:

public class PointPaymentService {

    public boolean pay(Gift gift) {
        // 具体逻辑
        System.out.println("支付【" + gift.getName() + "】积分成功");
        return true;
    }
}
1
2
3
4
5
6
7
8

物流配送系统:

public class ShippingService {

    public String shipGift(Gift gift) {
        // 具体逻辑
        System.out.println("【" + gift.getName() + "】进入物流系统");
        // 订单号
        String shippingOrderNo = "123";
        return shippingOrderNo;
    }
}
1
2
3
4
5
6
7
8
9
10

接下来就是融合3个子系统的礼品兑换类怎么使用呢:

public class GiftExchangeService {

    private QualifyService qualifyService ;
    private PointPaymentService pointPaymentService ;
    private ShippingService shippingService ;

    public void setQualifyService(QualifyService qualifyService) {
        this.qualifyService = qualifyService;
    }

    public void setPointPaymentService(PointPaymentService pointPaymentService) {
        this.pointPaymentService = pointPaymentService;
    }

    public void setShippingService(ShippingService shippingService) {
        this.shippingService = shippingService;
    }

    public void giftExchange(Gift gift) {
        // 资格校验
        if (qualifyService.isAvailable(gift)) {
            // 积分支付
            if (pointPaymentService.pay(gift)) {
                // 物流运输生成订单号
                String shippingOrderNo = shippingService.shipGift(gift);
                System.out.println("物流系统下单订单号:" + shippingOrderNo);
            }
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

通过3个 setter() 方法将3个子系统注入,然后通过曝露的 giftExchange() 进行礼品兑换。

来看看应用层的使用:

    public static void main(String[] args) {
        Gift gift = new Gift("U盘");
        GiftExchangeService giftExchangeService = new GiftExchangeService();

        giftExchangeService.setQualifyService(new QualifyService());
        giftExchangeService.setPointPaymentService(new PointPaymentService());
        giftExchangeService.setShippingService(new ShippingService());

        giftExchangeService.giftExchange(gift);
    }
1
2
3
4
5
6
7
8
9
10

将3个子系统设置到礼品兑换类中,然后进行礼品兑换。

运行结果:

校验【U盘】积分资格通过,库存通过
支付【U盘】积分成功
【U盘】进入物流系统
物流系统下单订单号:123
1
2
3
4

不过到现在为止,应用层还耦合了3个子系统,需要对3个子系统进行创建并设置到外观对象中,所以这里需要改改礼品兑换类:

public class GiftExchangeService {

    private QualifyService qualifyService = new QualifyService();
    private PointPaymentService pointPaymentService = new PointPaymentService();
    private ShippingService shippingService = new ShippingService();

    public void giftExchange(Gift gift) {
        // 资格校验
        if (qualifyService.isAvailable(gift)) {
            // 积分支付
            if (pointPaymentService.pay(gift)) {
                // 物流运输生成订单号
                String shippingOrderNo = shippingService.shipGift(gift);
                System.out.println("物流系统下单订单号:" + shippingOrderNo);
            }
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

让3个子系统在礼品兑换类初始化的时候就创建好,业务层就无需关注子系统的创建和设置了。

修改后的应用层:

    public static void main(String[] args) {
        Gift gift = new Gift("U盘");
        GiftExchangeService giftExchangeService = new GiftExchangeService();
        giftExchangeService.giftExchange(gift);
    }
1
2
3
4
5

这样子,子系统就只和外观类通信,应用层也只和外观类通信。3个子系统的处理和应用层完全没有联系。

运行结果:

校验【U盘】积分资格通过,库存通过
支付【U盘】积分成功
【U盘】进入物流系统
物流系统下单订单号:123
1
2
3
4

假如说目前我们礼品兑换包装类的版本是 1.0 ,后面礼品兑换的逻辑需要新增子系统也就是升级到 2.0 版本,这里可以考虑在礼品兑换包装类的1.0版本基础上往上抽象出一个抽象类,然后对于 2.0 的包装类使用一个新的实现类来实现逻辑,在这个新的包装类中注入所需要的子系统,然后业务层直接调用礼品兑换抽象类的抽象方法即可。这样做也是起到了一个版本控制的效果。


上次更新: 2020-08-21 09:02:51(10 小时前)