什么是门面模式?
门面模式(Facade Pattern),又叫外观模式。当调用者想与一个复杂的系统进行通信的时候,中间要有一个门面对象来简化这个通信过程。
为什么要用门面模式?
我们可以用去医院看病的过程来举个例子。去医院看病是非常伤脑筋的一件事,因为医院这个系统太复杂了,比如你要去某个科室看病,你需要先去挂号,挂完号去看医生,他又告诉你先去做个化验,化验完了还需要等结果……但如果医院给我们提供一个协调员小妹,让她帮我们跟医院打交道,我们只需要坐在那里等医生来给我们看病就好了!这个协调员小妹,就是我们说的门面对象
上面的这个门面对象,也叫门面类、外观类。这个门面对象为一个复杂的系统提供了一个简单的接口。与真正的子系统相比,门面对象可能提供的功能比较有限,但是却是我们最关心的功能。想象一下,如果你的程序里引入了一个第三方的类库,但是你只需要其中的一部分功能,使用外观功能可以帮助你屏蔽掉这个第三方类库中不需要的功能。
如何使用门面模式?
根据上面的介绍,我们可以自然而然的推测出门面模式要有两个角色:
门面角色:客户端调用这个角色的方法。这个角色需要知道相关的子系统的功能和责任,本角色会将客户端发来的请求委派到子系统中去完成。
子系统角色:真正完成请求的地方。每个子系统都不是一个类,而是一个类的集合。需要注意的是,不仅仅门面角色能调用子系统角色,真正的客户端也可以直接调用子系统。对于子系统而言,门面角色也仅仅是一个客户端。
我们用代码来说明之前去医院看病的例子。
// 挂号处
public class Registration {
public void register() {
// ...
}
}
// 诊察室
public class ConsultingRoom {
public void consult() {
// ...
}
}
// 化验科
public class Laboratory {
public void test() {
// ...
}
}
// 病人
public class Patient {
public static void main(String[] args) {
(new Registration()).register(); // 挂号
(new Laboratory().test()); // 化验
(new ConsultingRoom()).consult(); // 诊断
}
}
在没有门面角色的情况下,我们需要事必躬亲,每件事都需要自己去做。但作为一个病人,我们可能对医院这个系统不是那么熟悉,不知道可以看病的最佳流程。
并且,从软件分层的角度来看,我们也不应该知道子系统中每个部件的具体实现。因此,如果我们有个门面角色来帮我们完成这些事情,我们就可以省去很多的烦恼。
// 门面类
public class HospitalFacade {
public void serve() {
(new Registration()).register();
(new Laboratory().test());
(new ConsultingRoom()).consult();
}
}
// 病人
public class Patient {
public static void main(String[] args) {
(new HospitalFacade()).serve();
}
}
门面模式的代码很简单,甚至可以用加一层封装就能解释。想充分发挥这个模式的优势,你必须确保所有客户端代码仅通过外观来与子系统进行交互。此后客户端代码就不会因为子系统代码改变而受到影响。最多需要改变门面模式中的代码。
这个模式虽然很简单,但我们也需要注意一些事情。
注意
不能试图通过外观类来为子系统增加新的功能
门面模式的用意是为子系统提供一个集中化的和简化的沟通渠道,而不是向子系统中加入新的行为。新的行为应该通过修改原有子系统来实现。
门面角色可能成为一个与程序中所有类都耦合在一起的上帝对象