设计模式系列
创建型设计模式
Java 设计模式之静态工厂、工厂方法、抽象工厂和 Builder 模式的区别
结构型设计模式
前言
新的一年,立了新的 flag,设计模式的学习和总结,是一季度的重点。今天,我们迎来了结构型设计模式第二篇——外观模式。
外观模式,在 Android 开发的过程中,使用的频率极高。高到什么程度呢?可以说,每一位开发者都用过。
定义
外观模式(Facade),又被称为 “门面模式”。要求一个子系统的外部与其内部通信必须通过一个统一的对象进行,外观模式提供一个高层的接口,使得子系统更易于使用。
通俗点说,这个子系统可能是一个功能模块、也可能是一个 SDK,此子系统提供的功能统一由 Facade 类向外开放,当需要使用此子系统的功能时,都要调用 Facade 类中的方法。
这个 Facade 类就是所谓的 “统一的对象”,也是所谓的 “高层的接口”。除了 Facade 类,我们不需要关心子系统的其他代码,也不需要关心 Facade 类中的方法具体是怎么实现的,这极大降低了使用者的使用成本,也就是所谓的 “使得子系统更易于使用”。
说到这里,相信大家已经意识到,外观模式我们平时用的确实很多,尤其是在使用三方 SDK 时,很多都会采用这种模式。
比如很多人所熟知的友盟统计 SDK,我们只需要在 Activity 的 onResume()
和 onPause()
中简简单单地添加两句代码(如下程序清单 1 所示),就可以实现页面跳转历史、页面停留时长等统计功能,并将相应数据上传到友盟服务器。友盟提供的外观类是 MobclickAgent
,通过它就可以实现统计并上报的功能,调用者无需关心其实现细节。
@Override
public void onResume() {
super.onResume();
MobclickAgent.onResume(this);
}
@Override
public void onPause() {
super.onPause();
MobclickAgent.onPause(this);
}
使用场景
外观模式的使用场景,除了前面所说的 SDK ,还有更加广泛的场景,让我们来总结一下。
1、随着时间推移,一个系统往往会因演化、重构等因素变得越来越复杂,甚至会被完全替换。外观模式,可以为这样的系统提供一个简单、统一的接口,对外隐藏系统的复杂逻辑并隔离变化。
2、一个系统可能会包含多个层级,使用外观模式可以定义每一层的入口;如果这些层级之间存在功能调用,它们可以通过外观接口进行通信,降级层级之间的依赖与耦合。
3、当维护一个遗留的系统时,可能此系统已经难以维护和扩展,但因其含有重要功能,所以新的需求必须依赖它。
这时候,我们就可以为此遗留系统创建一个外观类,向外提供简单易用的外观接口,由外观类负责与此系统交互,就可以将此系统内的复杂代码隔离起来了。
示例
这段时间在做基础库 ZBase 的重构,就以其中的网络模块为外观模式做示例吧。
UML类图
先看下网络模块简易的 UML 类图:
解释
1、从 UML 类图中,我们不难发现,调用方 Client
要使用 SDK 中网络功能的话,要通过外观类 HttpHelper
。HttpHelper
中有一些接口( get、post、addHeader 等),这些接口提供了网络模块对外开放的功能。也就是说,把 HttpHelper
作为高层接口,外部与内部系统的通信都要经过 HttpHelper
。
2、我们还看到,这里面还用到了我们之前讨论过的 工厂方法模式。HttpClientFactory
是一个工厂,具体要生产什么样的工厂对象(KalleClient
、RetrofitClient
或者其他),以及这些工厂对象中具体是怎么样实现外观类对外开放的功能的,调用方 Client
都无需了解。也就是说,隔离了实现细节和变化。
总结
外观模式,称得上最简单的设计模式了,但也确实很好用、很常用,大家在做自己的 SDK 封装、为自己的项目划分模块划分层次,或者发布自己的开源库时,都可以实践起来了。
示例中的程序源码,稍后等我把 ZBase 重构得差不多了,会开放出来。欢迎到 Github Follow Me,也欢迎为我的开源库点个 Star。
感谢
- 《Android源码设计模式解析与实战》 何红辉 关爱民
- 《Android进阶之光》 刘望舒
- 在线绘图网站 ProcessOn