一、外观模式的核心思想
在真实的应用系统中,一个子系统可能由很多类组成。子系统的客户为了满足它们的需要,黑要和子系统中的一些类进行交互。客户和子系统的类进行直接的交互会导致客户端对象和子系统之间高度耦合。如下图所示,X和Y对子系统内A、B和C都有调用,它们之间是高度耦合。
外观模式为子系统提供了一个更高层次、更简单的接口,从而降低了子系统的复杂度和依赖,这使得子系统更易于使用和管理。外观是一个能为子系统和客户提供简单接口的类。当正确地应用外观时,客户不再直接与子系统中的类交互,而是与外观交互。外观承担与子系统中类交互的责任。实际上,外观是子系统与客户的接口,这样外观模式降低了子系统和客户的耦合度。如下图所示,在 X、Y 与 A、B、C之间增加一个 Facade 外观类,它们之间的调用只需要通过 Facade 来进行。
外观对象隔离了客户和子系统对象,从而降低了耦合度。当子系统中的类进行改变时,客户端不会像以前一样受到影响。尽管客户使用由外观提供的简单接口,但是当需要的时候,客户端还是可以视外观不存在,直接访问子系统中的底层次的接口。在这种情况下,它们之间的依赖/耦合度和原来一样。
外观模式也是由代理模式发展而来的,与代理模式类似,代理式是一对一的代理,而外观模式是一对多的代理。与装饰模式不同的是,装饰模式为对象增加功能,而外观模式则是提供一个简化的调用方式。一个系统可以有多个外观类,每个门面类都只有一个实例,可以使用单例模式实现。
外观模式中包含3种角色:目标类、外观类、客户端类。以计算机的加载和关闭过程为例,这3 类角色如下。
- 目标类:包括 CPU、内存和硬盘。
- 外观类:即为计算机类。
- 客户端类:即为用户。
它们之间的依赖关系如下图所示。
下面来看具体的实现。
(1) CPU类CPU.iava的源代码如下程序所示,其中定义了启动和关闭 CPU 的函数。
CPU类CPU.java
java
package structure.facade;
public class CPU {
public void startup(){
System.out.printin("启动CPU");
}
public void shutdown(){
System.out.println("关闭CPU");
}
}
(2) 内存类 Memory.java的源代码如下程序所示,其中定义了加载和清空内存的函数。
内存类Memory.java
java
package structure.facade;
public class Memory {
public void startup(){
System.out.printin("加载内存");
}
public void shutdown(){
System.out.println("清空内存");
}
}
(3) 硬盘类 Disk.java的源代码如下程序所示,其中定义了加载和卸载硬盘的函数。
硬盘类 Disk.java
java
package structure.facade;
public class Disk {
public void startup(){
System.out.printin("加载硬盘");
}
public void shutdown(){
System.out.println("卸载便盘");
}
}
(4) 外观模式类Computerjava的源代码如下程序所示,其中包含了CPU、内存和硬盘 3个类对象,并定义了启动和关闭计算机的函数,在启动和关闭时批量地启动和关闭CPU、内存和硬盘。
外观模式类 Computer.java
java
package structure.facade;
/**
* @author Minggg
* 外观模式
*/
public class Computer {
private CPU cpu;
private Memory memory;
private Disk disk;
public Computer(){
cpu = new CPU();
memory= new Memory();
disk = new Disk();
}
public void startup(){
System,out.printin("开始启动计算机");
cpu.startup();
memory.startup();
disk.startup();
Systemm.out.printin("启动计算机完成");
}
public void shutdown(){
System.out.printn("开始关闭计算机");
cpu.shutdown();
memory.shutdown();
disk.shutdown();
System.out.println("关闭计算机完成");
}
}
(5) 内存类 Memory.java的源代码如下程序所示,我们只需要调用 Computer.java 的函数来启动和关闭计算机,而不需要依次加载和关闭CPU、内存和硬盘。
用户类User.java
java
package structure.facade;
public class User {
public statie void main(String[] args){
Computer computer = new Computer();
computer.startup();
computer.shutdown();
}
}
运行该程序的输出如下:
java
开始启动计算机
启动CPU
加载内存
加载硬盘
启动计算机完成
开始关闭计算机
关闭 CPU
清空内存
卸载硬盘
关闭计算机完成
从程序的输出可以看出,通过 Computer 一个外观类即可实现计算机所有部件的控制,而不需要单独去控制其所有的部件,这正是外观模式的作用。
二、何时使用外观模式
外观模式可以将一些列复杂的类包装成一个简单的封闭接口。外观模式对客户屏蔽了复杂的子系统组件,并为一般用户提供了一个比较简单的程序设计接口。但是,它并没有限制高级用户在需要时使用深层次的、较复杂的类。
三、Java中的应用
根据外观模式的应用场景可知,在Java中,凡是为一个子系统提供统一的外部接口,而不需要了解子系统内部的类都属于外观模式的应用。这种应用场景很多,比如JDBC,它则屏蔽了与数据库进行连接、查询、更新、删除等一系列操作,因此它就属于外观模式的应用。在现在比较普遍的开源框架中,如Hibermate 就可以算是一种外观模式。