一、概念
外观模式(Facade)为子系统中的一组接口提供一个统一的高层接口,这个接口使得子系统更容易被使用或访问。外观模式又称为门面模式,它是一种对象结构型模式。
二、结构
外观模式结构如图1所示,主要有三种角色。
1、子系统角色(SubSystem):实现子系统功能,并对外提供接口
2、外观角色(Facade):封装子系统功能,对外提供满足客户需求的接口
3、客户角色(Client):通过外观角色所提供的接口,实现所需要的功能
图1
三、例子
下面我们将通过一个具体的例子来说明外观模式是如何实现的。每台电脑(Computer)都有处理器(CPU)、内存(Memory)和硬盘(Disk),在computer启动和关闭的时候,相应的组件(CPU、Memory和Disk)也会开启和关闭,如图2所示。
客户(Client)只需调用外观类(Computer)中的startup()方法和shutdown()方法就可以实现电脑的开启和关闭,而不用关心底层组件(CPU、Memory和Disk)是怎么实现开启和关闭功能的,从而使客户更加容易的使用系统。下面是代码的具体实现。
1、子系统类
CPU.java
package com.yushen.designmodel.facade;
/**
* CPU子系统类
*/
public class CPU {
public void start()
{
System.out.println("CPU is startup...");
}
public void shutdown()
{
System.out.println("CPU is shutdown...");
}
}
Memory.java
package com.yushen.designmodel.facade;
/**
* Memory子系统类
*/
public class Memory {
public void start()
{
System.out.println("Memory is startup...");
}
public void shutdown()
{
System.out.println("Memory is shutDown...");
}
}
Disk.java
package com.yushen.designmodel.facade;
/**
* Disk子系统类
*/
public class Disk {
public void start()
{
System.out.println("Memory is startup...");
}
public void shutdown()
{
System.out.println("Memory is shutDown...");
}
}
2、外观类
Computer.java
package com.yushen.designmodel.facade;
/**
* 门面(Facade)类
*/
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.println("Computer startup begin");
cpu.startup();
disk.startup();
memory.startup();
System.out.println("Computer startup end");
}
//将子系统关闭功能组合,并封装成对外关闭接口
public void shutdown(){
System.out.println("Computer shutdown begin");
cpu.shutdown();
disk.shutdown();
memory.shutdown();
System.out.println("Computer shutdown end");
}
}
3、客户类
Client.java
package com.yushen.designmodel.facade;
/**
* 客户端类
*/
public class Client {
public static void main(String[] args) {
Computer computer = new Computer();
computer.startup();
computer.shutdown();
}
}
此外,门面模式还有一个好处就是能够有选择性的暴露方法。子系统中定义的方法可以分成两种,一种是给外部调用的,一种是给子系统内部相互调用的。如果有了外观类(Facade),那么用于子系统内部模块之间相互调用的方法就不用暴露给子系统外部了。参照图1,假如有SystemA、SystemB和SystemC三个子系统,每个子系统都有外部调用方法和内部调用方法两种,子系统的具体代码如下。
package com.yushen.designmodel.facade;
/**
* 子系统A
*/
public class SystemA {
//提供给子系统外部使用的方法
public void A1(){};
//子系统内部模块之间相互调用时使用的方法
private void A2(){};
private void A3(){};
}
package com.yushen.designmodel.facade;
/**
* 子系统B
*/
public class SystemB {
//提供给子系统外部使用的方法
public void B1(){};
//子系统内部模块之间相互调用时使用的方法
private void B2(){};
private void B3(){};
}
package com.yushen.designmodel.facade;
/**
* 子系统C
*/
public class SystemC {
//提供给子系统外部使用的方法
public void C1(){};
//子系统内部模块之间相互调用时使用的方法
private void C2(){};
private void C3(){};
}
由上述代码可知,A、B、C三个子系统中均存在内部调用的方法,这些方法完全没必要让客户(Client)知道。因此,可以设计一个外观(Facade)类来屏蔽子系统中内部调用方法的实现细节,而仅仅提供一些外部使用的方法。Facade和Client的代码如下。
package com.yushen.designmodel.facade;
/**
* Facade类
*/
public class Facade {
private SystemA systemA;
private SystemB systemB;
private SystemC systemC;
public Facade(){
systemA = new SystemA();
systemB = new SystemB();
systemC = new SystemC();
}
public void test(){
systemA.A1();
systemB.B1();
systemC.C1();
}
}
package com.yushen.designmodel.facade;
/**
* 客户端类
*/
public class Client {
public static void main(String[] args) {
Facade facade = new Facade();
//客户类通过外观类调用子系统的对外方法
facade.test();
}
}
四、应用场景
五、总结
总的来说,外观模式(门面模式)具有如下几个特点。
- 松散耦合
通过引入外观模式,松散了客户端与子系统的耦合关系,让子系统内部的模块能更容易扩展和维护
- 简单易用
客户端根本不需要知道子系统内部的实现,或者根本不需要知道子系统内部的构成,它只需要跟外观类交互即可
- 更好的划分访问层次
有些方法是对系统外的,有些方法是系统内部相互交互的使用的。子系统把那些暴露给外部的功能集中到门面中,这样就可以实现客户端的使用,很好的隐藏了子系统内部的细节