第十一章 外观模式
一、外观模式
在日常开发中,注册一个用户需要进行如下操作:验证手机验证码、生成用户类、存储至数据库、初始化用户积分等等操作。但是 客户端只需要调用一个 UserService.register() 即可,具体的其他对象的操作都交给 UserService 的实现来完成。
还有如 MVC 模式中,Controller 层中通过调用 service 来解耦 Controller 层与 Dao 层,隔离各个层次,实现层次化结构。
于 controller 而言,service 就是外观类,由service 来处理多个dao的交互。
1.1 定义
外观模式,又称为门面模式,是一种使用频率非常高的结构型设计模式,通过引入一个外观对象来简化客户端与子系统之间的交互,为复杂的子系统调用提供一个统一的入口,降低子系统与客户端的耦合度,且客户端调用非常方便。
外观模式是迪米特法则的一种具体实现,通过引入一个新的外观角色可以降低原油系统的复杂度,同时降低客户类与子系统的耦合。
1.2 外观模式
在日常生活中,自己泡茶和去茶馆喝茶的区别类似于上图显示的这样。自己泡需要与 热水、差距、茶叶 进行交互(系统耦合度十分的高),而去茶馆喝茶只需要与服务员(Facade)进行交互即可。
1.3 外观模式中的几个角色:
- Facade - 外观角色
- 由客户端调用其中的方法,来访问相关子系统的功能
- 由外观角色将客户端的请求委派到具体子系统中
- SubSystem - 子系统角色
- 系统中可以存在一个或多个子系统角色
- 每个可以被客户端调用,也可以被外观角色调用,用于处理请求
- 子系统并不知道外观的存在,与它而言,外观角色仅仅是另一个客户端
二、完整实现
/**
* 外观模式
*/
class SubSystemA {
public void sayHello() {
System.out.println("大家好,我是系统A");
}
}
class SubSystemB {
public void byebye() {
System.out.println("再见,我是系统B");
}
}
class SubSystemC {
public void o() {
System.out.println("i don't wanna see you anymore.");
}
}
class Facade {
private SubSystemA a = new SubSystemA();
private SubSystemB b = new SubSystemB();
private SubSystemC c = new SubSystemC();
public void bb(){
a.sayHello();
c.o();
b.byebye();
}
}
public class FacadePattern {
public static void main(String[] args) {
// 通过外观类 Facade 减少了客户端与各个子系统的直接交互,降低耦合度
final Facade facade = new Facade();
facade.bb();
}
}
三、抽象外观类
在标准外观模式中,如果需要增加、删除或更换与外观类交互的子系统类,必须修改外观类或客户端的代码。这将违背开闭原则。
可以引入抽象外观类来对系统进行改进,客户端针对抽象外观类进行编程。
四、总结
优点
- 对客户端屏蔽子系统组件,减少客户端所需处理的对象数目,使子系统的使用更加容易
- 客户端与子系统间关联的对象会减少
- 实现了子系统和客户端之间的松耦合,子系统的变化只需要调整外观类即可
- 子系统的修改不会影响其他子系统,且子系统内部修改不会影响到外观类
缺点
- 由外观类来调用子系统类,减少了客户端直接调用时的灵活性和可变性
- 如果设计不当,增加子系统时可能会修改外观类,违背了开闭原则
适用场景
- 当需要为访问一系列复杂的子系统对象提供简单入口时,可以使用外观模式
- 外观类可以将子系统与客户端解耦,从而提高子系统的独立性和可移植性
- 在层次化结构中,可以使用外观模式定义系统中的每一层入口。层与层之间不直接产生联系,而通过外观类建立联系,降低层之间的耦合度