一、概述
外观模式,又叫做门面模式。
外观模式将一个系统中的每一项称为一个子系统,为这一组子系统提供一个高层接口,这个接口可以使得这一子系统更加容易被人使用。
通俗的来讲就是,将一系列的行为封装为一个接口,在这个接口中统一来调用这些行为,这样在程序员使用的时候就不需要一个一个接口的调用,而只需要调用统一的接口就可以了,以此来降低一整个流程的复杂度。
但是我们需要注意的是,并不是说,我们只对外暴露一个统一的接口,而细节要全部隐藏,其实Facade只是为了方便一般用户调用,但是我们有特殊的需求需要访问某个或者某些个别子系统时,也可以自己通过调用各个子系统来完成自己的需求。
Facade对于子系统来说,其实就是另一个客户端而已。
通俗一点来说,我们买电脑的时候,大致都有两种选择,要么自己购买零件组装一台,要么就购买某品牌下已经装好的电脑整机,
而购买电脑整机就类似于调用我们的Facade,我们不需要过于关注一些细节,他会来帮我们实现,
而购买零件自己组装一台我们就需要将零件一步步自己拼成一个电脑,这整个过程中都需要我们亲自动手把控。
同样的,对于一些电脑小白来说显然购买整机会更加的方便和安全,而对于一些电脑高手,则会选择自己来主动的选择配置一台电脑,这也是对上文中一般用户以及有特殊需求的用户的说明。
二、角色职责与UML
2.1 角色与职责
外观模式的角色划分特别简单,只有两个
Facade
- 知道哪些子系统类负责处理请求
- 将客户的请求代理给适当的子系统对象
Subsystem classes
- 实现了子系统的功能
- 处理由Facade对象指派的任务
- 不知道Facade的任何信息
2.2 UML图
三、示例
我们就以电脑为例,进行一个小的Demo演示
首先我们需要创建一些子系统来系统电脑的组装过程,篇幅有限就以Cpu、Ram以及Rom来代表吧
/**
* CPU
*
* @author ZhongJing </p>
*/
public class Cpu {
private String brand;
public Cpu(String brand) {
this.brand = brand;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public void assembly() {
System.out.println("组装Cpu: " + brand);
}
@Override
public String toString() {
return "Cpu{" +
"brand='" + brand + '\'' +
'}';
}
}
/**
* 内存
*
* @author ZhongJing </p>
*/
public class Ram {
private String brand;
public Ram(String brand) {
this.brand = brand;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public void assembly() {
System.out.println("组装内存: " + brand);
}
@Override
public String toString() {
return "Ram{" +
"brand='" + brand + '\'' +
'}';
}
}
/**
* 硬盘
*
* @author ZhongJing </p>
*/
public class Rom {
private String brand;
public Rom(String brand) {
this.brand = brand;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public void assembly() {
System.out.println("组装硬盘: " + brand);
}
@Override
public String toString() {
return "Rom{" +
"brand='" + brand + '\'' +
'}';
}
}
然后我们为这一子系统创建一个门面,来表示品牌的电脑整机替我们组装电脑的过程
/**
* 电脑整机
* @author ZhongJing </p>
*/
public class CompleteMachine {
private Cpu cpu = new Cpu("酷睿i5");
private Ram ram = new Ram("金士顿16G");
private Rom rom = new Rom("金士顿1T");
public void install() {
cpu.assembly();
ram.assembly();
rom.assembly();
}
}
接下来看看,调用门面以及自己调用子系统的不同之处
/**
* 测试
*
* @author ZhongJing </p>
*/
public class MainTest {
public static void main(String[] args) {
CompleteMachine completeMachine = new CompleteMachine();
completeMachine.install();
System.out.println("---------- 我是邪恶的分割线 ----------");
Cpu cpu = new Cpu("酷睿i7");
Ram ram = new Ram("金士顿32G");
Rom rom = new Rom("金士顿2T SSD");
cpu.assembly();
ram.assembly();
rom.assembly();
}
}
运行结果如下:
组装Cpu: 酷睿i5
组装内存: 金士顿16G
组装硬盘: 金士顿1T
---------- 我是邪恶的分割线 ----------
组装Cpu: 酷睿i7
组装内存: 金士顿32G
组装硬盘: 金士顿2T SSD
通过结果我们可以看到,在调用门面时,我们只需要通过门面给我们提供的方法就可以对整个子系统进行调用,非常方便。
而我们想要自己独特定制某些功能时,我们也可以手动的去调用各个子系统来完成我们的需求。