前言
门面模式,是指提供一个统一的接口去访问多个子系统的多个不同的接口,它为子系统中的一组接口提供一个统一的高层接口。使得子系统更容易使用。日志框架slf4J是门面模式最经典的应用场景。
本节,我们就门面模式,展开详细介绍。
1. 门面模式中的角色
1.1 门面角色(Facade)
客户端可以调用这个角色的方法。此角色知晓相关的(一个或多个)子系统的的功能和责任。在正常情况下,本角色会将所有从客户端发来的请求委派到相应的子系统去。
1.2 子系统角色(Subsystem)
可以同时有一个或者多个子系统。每一个子系统都不是一个单独的类,而是一个类的集合。每一个子系统都可以被客户端直接调用,或者被门面角色调用。子系统并不知道门面的存在,对于子系统而言,门面仅仅是另一个客户端而已。
2. 代码示例
2.1 定义门面角色
package com.wanlong.design_pattern.structure.facade;
/**
* @author wanlong
* @version 1.0
* @description: 门面角色
* @date 2022/9/19 16:31
*/
public class Facade {
private SubSystemA a = new SubSystemA();
private SubSystemB b = new SubSystemB();
private SubSystemC c = new SubSystemC();
//对外接口
public void doA() {
this.a.doA();
}
//对外接口
public void doB() {
this.b.doB();
}
//对外接口
public void doC() {
this.c.doC();
}
}
2.2 定义子系统角色
2.2.1 定义子系统A
package com.wanlong.design_pattern.structure.facade;
/**
* @author wanlong
* @version 1.0
* @description:
* @date 2022/9/19 16:30
*/
public class SubSystemA {
public void doA(){
System.out.println("doing A stuff");
}
}
2.2.2 定义子系统B
package com.wanlong.design_pattern.structure.facade;
/**
* @author wanlong
* @version 1.0
* @description:
* @date 2022/9/19 16:30
*/
public class SubSystemB {
public void doB() {
System.out.println("doing B stuff");
}
}
2.2.3 定义子系统C
package com.wanlong.design_pattern.structure.facade;
/**
* @author wanlong
* @version 1.0
* @description:
* @date 2022/9/19 16:30
*/
public class SubSystemC {
public void doC(){
System.out.println("doing C stuff");
}
}
2.4 客户端调用
@Test
public void testFacade(){
Facade facade = new Facade();
facade.doA();
facade.doB();
facade.doC();
}
代码运行结果:
doing A stuff
doing B stuff
doing C stuff
3. 总结
3.1 优缺点
3.1.1 优点
- 简化了调用过程,无需深入了解子系统,以防给子系统带来风险。
- 减少系统依赖、松散耦合
- 更好地划分访问层次,提高了安全性
- 遵循迪米特法则,即最少知道原则
3.1.2 缺点
- 当增加子系统和扩展系统行为时,可能容易带来未知风险
- 不符合开闭原则
- 某些情况下可能违背单一职责原则
3.2 使用场景
问:在什么情况下可以使用门面模式?
答:为一个复杂子系统提供一个简单接口。
子系统往往因为不断演化而变的越来越复杂,使用门面模式可以使得子系统更具有可复用性。Facade模式可以提供一个简单的默认视图,对大多数用户来说这个视图已经足够用了。而那些需要进一步继承的用户可以越过Facade层直接对子系统进行继承。
一般而言,子系统和其他子系统之间、客户端与实现化层之间存在着很大的依赖性。引入Facade模式将一个子系统与它的客户端及其他子系统分离,可以提高子系统的独立性和可移植性。
在构建一个层次化的系统时,可以使用 Facade模式定义系统中每一层的入口。如果层与层之间是相互依赖的,则可以限定它们仅通过Facade进行通信,从而简化层与层之间的依赖关系。
这有点像现在很多公司系统结构层次,web层访问聚合服务层、聚合服务层访问微服务层、微服务层访问底层dao层、dao层访问DB。类似下图。通过微服务拆分粒度变细,以及分层,正常情况限制服务调用需要层层传递调用,那么在顶层的调用者其实是感知不到具体接口内部有多复杂的,解耦了系统之间的依赖关系。
3.3 常用场景
- commons提供的DBUtils类
- Spring JDBC工具类JdbcUtils
- slf4j日志框架使用(门面模式最经典的应用)
- tomcat 的请求门面RequestFacade,ResponseFacade
3.4 注意
初学者往往以为通过继承一个门面类便可以在系统中加入新的行为,这是不合理的。门面模式的用意是,为子系统提供一个集中化和简化的沟通管道,而不能向子系统加入新的行为。以医院为例,接待员并不是医护人员,接待员并不能为病人提供医疗服务。
4. 扩展文献
关于slf4j实现原理
以上,本人菜鸟一枚,如有问题,请不吝指正。