外观模式(Facade Pattern)
定义
定义了一个高层、统一的接口,外部与通过这个统一的接口对子系统中的一群接口进行访问
结构
- 外观(Facade)角色:为多个子系统对外提供一个共同的接口。
- 子系统(Sub System)角色:实现系统的部分功能,客户可以通过外观角色来访问它。
- 客户(Client)角色:通过一个外观角色访问各个系统的功能。
类图
例子
家中有许多电器 每次出门都需要挨个关闭,回来再挨个开启很麻烦。 可以加一个控制器来一键开关
代码
public class Facade{
SubSystemA_Light light;
SubSystemB_Television television ;
SubSystemC_Aircondition aircondition;
//传参
public Facade(SubSystemA_Light light,SubSystemB_Television television,SubSystemC_Aircondition aircondition){
this.light = light;
this.television = television ;
this.aircondition =aircondition;
}
//起床后一键开电器
public void on{
System.out.prinln("起床了");
light.on();
television.on();
aircondition.on();
}
//睡觉时一键关电器
System.out.prinln("睡觉了");
light.off();
television.off();
aircondition.off();
}
}
客户端代码
public class Customer{
public static void main(String[] args){
{
//实例化电器类
SubSystemA_Light light = new SubSystemA_Light();
SubSystemB_Television television = new SubSystemB_Television();
SubSystemC_Aircondition aircondition = new SubSystemC_Aircondition();
//传参
Facade facade = new Facade(light,television,aircondition);
//客户端直接与外观对象进行交互
facade.on;
System.out.prinln("可以看电视了");
facade.off;
System.out.prinln("可以睡觉了");
作用
解耦客户类与子系统类,降低原有系统复杂度 提高客户端的便捷性,使其无需关心子系统的工作细节即可调用相关功能
实际应用
Spring Boot WebMvcConfigurer
在Spring Boot中,外观模式(Facade Pattern)通常用于简化与框架或库的交互。
一个典型的例子是Spring Boot的WebMvcConfigurer接口。在使用Spring MVC时,通常需要许多配置和自定义选项,例如添加自定义拦截器、消息转换器、异常处理器等。但是,将这些选项直接添加到WebMvcConfigurer接口中可能会导致代码混乱和难以维护。
因此,Spring Boot使用外观模式,提供了一个WebMvcConfigurerAdapter类,该类允许开发人员通过覆盖一些简单方法来完成配置,而不必直接修改复杂的WebMvcConfigurer接口。
另一个例子是Spring Boot的JdbcTemplate类,该类是用于与数据库交互的简单模板类。JdbcTemplate隐藏了所有与JDBC API相关的细节,并提供了简单的方法来执行SQL查询和更新。通过这种方式,JdbcTemplate充当了一个外观,简化了与数据库的交互。
因此,在Spring Boot中,外观模式被广泛应用于简化与框架和库的交互。
SLf4j
SLF4J是简单的日志外观模式框架,抽象了各种日志框架例如 Logback、Log4j、Commons-logging 和 JDK 自带的 logging 实现接口。它使得用户可以在部署时使用自己想要的日志框架。
SLF4J 没有替代任何日志框架,它仅仅是标准日志框架的外观模式。如果在类路径下除了 SLF4J 再没有任何日志框架,那么默认状态是在控制台输出日志。
日志处理框架 Logback 是 Log4j 的改进版本,原生支持SLF4J(因为是同一作者开发的),因此 Logback+SLF4J 的组合是日志框架的最佳选择,比 SLF4J+其它日志框架 的组合要快一些。而且Logback的配置可以是XML或Groovy代码。
缺点
在不引入抽象外观类的情况下,增加新的子系统可能需要修改外观类或客户端源代码,违背开闭原则 不能很好地限制客户使用子系统类,如果客户访问子系统类做太多的限制则减少了可变性和灵活性
场景
- 要为一个复杂的子系统对外提供一个简单的接口
- 提供子系统的独立性
- 客户程序与多个子系统时间存在很大的依赖性
与适配器模式的区别 外观模式的实现核心主要是——由外观类去保存各个子系统的引用,实现由一个统一的外观类去包装多个子系统类,然而客户端只需要引用这个外观类,然后由外观类来调用各个子系统中的方法。 这样的实现方式非常类似适配器模式,然而外观模式与适配器模式不同的是:适配器模式是将一个对象包装起来以改变其接口,而外观是将一群对象 ”包装“起来以简化其接口。它们的意图是不一样的,适配器是将接口转换为不同接口,而外观模式是提供一个统一的接口来简化接口。