在软件开发中,往往需要同多个子系统打交道。使用者往往需要了解各个子系统的接口,这会造成开发成本的提升。如果我们将系统看作一个黑盒,黑盒负责与子系统进行通讯,那么使用者就无需了解系统内部实现即可使用这个系统。外观模式就相当于一个黑盒子,将系统内的接口“保护”起来,并供给用户使用。
外观模式
外观模式(Facade):外观模式也叫门面模式,可为复杂的子系统提供一个调用的接口封装子系统使得这些子系统更便于开发人员的使用。外部应用程序无需关心子系统的具体实现,可以大大降低系统复杂度,提升程序的可拓展性。外观模式是迪米特法则的典型应用。
迪米特法则:只与你的直接朋友交谈,不跟“陌生人”说话(Talk only to your immediate friends and not to strangers)。其含义是:如果两个软件实体无须直接通信,那么就不应当发生直接的相互调用,可通过第三方转发该调用。其目的是降低类之间的耦合度,提高模块的相对独立性。
在项目的开发中,外观模式是我们使用广泛的一种模式。你肯定有过将一系列接口封装成一个工具类以供外部调用的经历。这就是外观模式的简单体现。在开源库、开源框架以及第三方SDK中,外观模式就被广泛应用。
外观模式的结构
- 外观(Facade):封装多个子系统,对外提供一个可供调用的外部接口。
- 子系统(SubSystem):即系统的各个组成部分,使用者可通过外观提供的接口访问子系统。
实际应用场景
- 工具类:例如密码工具类等
- 中间件的封装
- 开源类库
示例
在项目中,我们通常需要对用户上传的图像进行压缩处理。我们可能需要将复杂的图像压缩算法进行封装,并使用一个统一的接口便于开发人员日后的调用和维护。这里我们使用外观模式来实现。
首先,我们创建用于图像压缩的逻辑(即子系统),这里具体压缩过程不予展示,仅展示设计模式的基本结构。
ImageReader.java
package com.yeliheng.facade;
/**
* 子系统-图像读取器
*/
public class ImageReader {
public ImageReader() {
//TODO:图像读取逻辑...
System.out.println("读取图像!");
}
}
这个子系统类用于图形的读取。
ImageCompression.java
package com.yeliheng.facade;
/**
* 子系统-图像压缩器
*/
public class ImageCompression {
public void png(ImageReader reader) {
//TODO: 图像压缩逻辑...
System.out.println("图像已被压缩,输出格式: png");
}
public void jpg(ImageReader reader) {
//TODO: 图像压缩逻辑...
System.out.println("图像已被压缩,输出格式: jpg");
}
}
在子系统ImageCompression中,我们提供了两种压缩格式:png和jpg。
接着我们创建外观类。
CompressFacade.java
package com.yeliheng.facade;
/**
* 外观
*/
public class CompressFacade {
private ImageReader imageReader = new ImageReader();
private ImageCompression compression = new ImageCompression();
public void compress() {
compression.jpg(imageReader);
}
}
可以看到在外观类中,我们将调用图像压缩的方法进行了封装,在compress()方法中统一调用。这样,开发者在使用的时候,无需关心压缩算法的实现,可以直接调用外观类中的压缩方法就可以完成图像的压缩。大大减小工程复杂性,提高开发效率。
最后我们就可以使用写好的外观模式了。
Main.java
package com.yeliheng.facade;
public class Main {
public static void main(String[] args) {
System.out.println("开始进行图像压缩");
CompressFacade compressFacade = new CompressFacade();
compressFacade.compress();
}
}
我们实例化一个CompressFacade类,对类中的compress进行调用即可。
最终输出结果如下:
外观模式的优缺点
优点
- 降低了子系统与调用者间的耦合度,使得系统成为一个黑盒。
- 降低了开发人员阅读源码的成本,提升项目的可维护性。
缺点
- 增加子系统可能需要修改外观类和调用者的代码,这违反了“开闭原则”。
- 过度使用会造成系统类过多接口的暴露,可能造成无法预料的问题。
总结
外观模式是一种很日常的设计模式,它常常无意间出现在我们的开发中。我们可以通过这种设计模式减小调用者使用系统的难度,将复杂的子系统进行封装,提升系统的可维护性和拓展性。
本文示例的完整源代码参见:Github