秒懂设计模式之外观模式(Facade Pattern)

[版权申明] 非商业目的注明出处可自由转载
博文地址:https://blog.csdn.net/ShuSheng0007/article/details/116428733
出自:shusheng007

设计模式汇总篇,一定要收藏:

永不磨灭的设计模式(有这一篇真够了,拒绝标题党)

文章目录

  • 概述
    • 类型
    • 难度
  • 定义
  • 使用场景
  • UML 类图
  • 实例
  • 第一步,确定需要调用的子模块
  • 第二步,创建外观类
  • 第三步,客户端使用
  • 技术要点总结
  • 优缺点
    • 优点
    • 缺点
  • 总结

概述

Facade Pattern 有时也翻译成面板模式,是一个使用频率极高的设计模式。思想非常简单,对外提供简单的交互接口,隐藏内部的复杂性。

这在现实世界实在是太常见了,只要世界发生了混乱,这个模式就会有用武之地。此种机会的精髓就是: !一般是行业初期多家服务商各种竞争还谁都没有胜出的时候,等到了后期决出老大后你这个生意也就凉了,如果一直决不出,那就可以一直做。

例如移动广告最开始发展时,市面上做移动广告的少说也有几十上百家,关键是由于没有决出行业龙头,好多家实力差不多,用户就面临要一个一个接入这些广告sdk的尴尬,那如果此时有一家公司出个统一的SDK聚合一下这些商家,用户只需要与这一家对接多好,你是不是觉得你找到了个一本万利的创业机会了,不好意思你能想到的会外观设计模式的人早就这么做了,所以说设计模式重要吧…

不仅是移动广告,任何符合外观模式的情况,都可以尝试去创业,成功案例汗牛充栋。随便说几个软件行业的:ShareSDK: 聚合社交媒体的;Ping++:聚合支付的,还有聚合各种小程序开发的,聚合各社交平台发布文章或者视频的等等,数不胜数。

类型

结构型(structural)

难度

1颗星

定义

提供一个高层次的接口,使得子系统更易于使用

使用场景

当你的程序有很多个模块,或者说子系统。你希望给用户提供一个统一的操作界面类,而不是让用户分别与这些模块交互。

一种设计是:给用户提供一套面板方用来法完成一般性的功能,如果面板提供的方法不能满足用户需求,用户还可以直接使用具体模块的功能来达到自己的目的。
另一种设计是:用户完全看不到各子模块,所有操作必须通过面板来完成,如果面板没有提供相应的功能,那也就gg了。

UML 类图

上一张手撕的UML类图
秒懂设计模式之外观模式(Facade Pattern)_第1张图片

从上图可见,外观模式极其简单,只包含两个组成部分

  • Facade

就这个一个关键部分,里面引用各个子模块,然后对外提供统一的接口

  • 其他模块

要被隐藏的那些独立功能模块,或者说是子系统

实例

王二狗公司大老板最近突然对他们正在开发的商城项目感了兴趣,所以要求他们出各种各样的报表。这可苦了二狗他们了,因为大老板要求的报表数据来自不同的子系统,这些子系统相互之间还有依赖,要想获得一份完整的报表,需要访问好多个模块…

前端负责生成报表的那小子都怒了:后端是一帮sb吗?我就拿几个报表数据丫的让我先调这个API再调那个API,我tm就生成一份报表,前前后后调用了十几个API,涉及好几个系统,我看你们都tm应该A雷劈!二狗他们也不敢说话,确实比较扯,最后二狗决定要扭转这种不利的局面,经过分析,他选择了外观设计模式。

第一步,确定需要调用的子模块

确定我们要使用面板隐藏的子模块,此处假设有3个子模块

//订单系统
public class OrderSys {
    public String getOrderNum(){
        System.out.println("获取订单号");
        return "123456";
    }
}
//支付系统
public class PaymentSys {
    private OrderSys orderSys;
    public PaymentSys(OrderSys orderSys) {
        this.orderSys = orderSys;
    }
    public BigDecimal getOrderAccount(String orderNum){
        System.out.println(String.format("获取%s订单支付金额",orderNum));
        return BigDecimal.valueOf(500);
    }
}
//物流系统
public class DeliverySys {
    public int getDeliveryTime(){
        System.out.println("获取配送耗时");
        return 30*60;//30分钟
    }
}

第二步,创建外观类

这个模式实在是太简单了,基本没什么可说的。这个外观类就是引用其他功能模块,完成相关的功能对外暴露操作接口。

例如本例中的外观类ReportFacade使用了OrderSysPaymentSysDeliverySys 3个子模块来完成一个生成报表的功能,客户端只需要通过此方法就可以生成报表了,不用关心那些子模块。

public class ReportFacade {

    public void generateReport() {
        OrderSys orderSys = new OrderSys();
        PaymentSys paymentSys = new PaymentSys(orderSys);
        DeliverySys deliverySys = new DeliverySys();

        final String orderNum = orderSys.getOrderNum();
        System.out.println(String.format("\n报表\n--------------------------------------------\n" +
                        "订单号:%s | 金额:%s元 | 配送耗时:%s分钟",
                orderNum,
                paymentSys.getOrderAccount(orderNum).toPlainString(),
                String.valueOf(deliverySys.getDeliveryTime() / 60))
        );
    }
}

第三步,客户端使用

public class FacadeClient {
    public void printReport(){
        new ReportFacade().generateReport();
    }
}

输出

获取订单号
获取123456订单支付金额
获取配送耗时

报表
--------------------------------------------
订单号:123456 | 金额:500元 | 配送耗时:30分钟

可见客户端只于外观类交互,完全不用与具体的子模块交互。

技术要点总结

过于简单基本没啥说的,唯一注意的一点是大部分的外观模式没有限制客户端直接使用子系统。也就是说如果用户遇到了通过外观方法无法完成的功能,可以自己调用相关子系统去完成。

优缺点

优点

极大的降低了客户端的复杂性

缺点

增加了一层,所以当子系统改变时,外观类相应的需要维护。

总结

设计模式值得你可以练习!

最后,如果你从本文中有所收获,可否点赞转发支持一下博主,你小小的鼓励,是激发博主持续写作的动力…

GitHub源码地址:design-patterns

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