文章目录
引言
软件开发有点像烹饪一道美味佳肴,涉及的材料和步骤可能会让人眼花缭乱。就像在一家大型餐厅厨房中,有许多不同的厨房工具和设备,而每位大厨只需专注于自己的拿手绝活。但是,如果每位大厨都在独立操作,可能就会出现混乱。在这个时候,外观模式就像一位负责整个厨房协调工作的主厨,为客人端上一道道精致的菜肴,而客人无需关心每个食材的具体来源和烹饪过程。
外观模式简介
定义与用途
外观模式又叫门面模式,是一种结构型设计模式,提供了一个统一的接口,以简化底层系统的复杂性。通过定义一个高层接口,客户端与子系统的交互变得更加简单,同时降低了客户端与子系统之间的耦合度。
实现方式
外观模式包含以下主要角色:
外观(Facade): 在外观模式中,外观类是核心。它被客户端调用,知道如何将客户端的请求委派给适当的子系统进行处理。
子系统(Subsystems): 子系统是外观的客户端。它包含了处理外观类指派的任务的具体类。
实现方式相对简单:
创建一个外观类,该类提供了一个简化接口,用于与系统中的一组接口进行交互。
外观类将客户端的请求委派给系统中的各个子系统。
使用场景
外观模式适用于以下场景:
- 简化复杂系统接口: 当一个系统包含许多复杂的子系统时,每个子系统都有自己的接口,而客户端需要与多个子系统交互,这时引入外观模式可以简化这些接口,提供一个更高层次、更简单的接口给客户端使用。
- 隐藏子系统的复杂性: 外观模式通过提供一个统一的接口,将子系统的复杂性隐藏起来,使得客户端不必了解子系统的具体实现,从而降低了系统的耦合度。
- 系统分层结构: 当系统分为多个层次结构时,每个层次都有自己的接口,而上层需要与多个下层交互。外观模式可以在每个层次中引入外观,提供一个简单的接口供上层使用,降低了层次间的耦合度。
- 封装与解耦: 外观模式封装了系统的复杂性,提供了一个简单的接口,使得客户端不必关心系统内部的复杂逻辑。这种封装有助于解耦,使得系统的变化不会影响到客户端。
优势与劣势
优势
- 简化了客户端与子系统之间的交互,降低了耦合度。
- 对客户端隐藏了子系统的具体实现,提高了系统的安全性。
- 外观类的存在使得系统更容易维护和扩展。
劣势
- 如果系统变得更加复杂,可能需要修改外观类,引入新的问题。
- 违反了开闭原则,对修改开放,对扩展封闭。
外观模式在Spring中的应用
Spring AOP(面向切面编程): AOP 是 Spring 框架的一个核心模块,用于处理横切关注点,例如事务管理、日志记录等。在AOP中,切面(Aspect)充当了外观角色,它封装了横切关注点的逻辑,并提供了一个简单的接口供客户端使用。通过引入AOP外观,开发者可以在不修改原有业务逻辑的情况下,实现诸如事务、日志等横切关注点。
Spring MVC(Model-View-Controller): 在Spring MVC中,控制器(Controller)充当了外观角色,它负责接收用户请求、调用业务逻辑处理器、选择视图进行展示。控制器封装了复杂的请求处理流程,提供了一个简单的接口供前端控制器(DispatcherServlet)使用。这样,前端控制器就无需关心具体的请求处理细节。
Spring Data(数据访问): Spring Data是Spring框架的一个子项目,用于简化数据访问的开发。在Spring Data中,各种数据访问技术(如JPA、Hibernate、MongoDB等)充当了外观角色,它们封装了底层数据访问细节,提供了一致的数据访问接口供开发者使用。开发者无需关心底层数据访问技术的差异,通过统一的接口即可进行数据操作。
Spring Security(安全框架): Spring Security用于处理应用程序的安全性问题,包括身份验证、授权等。在Spring Security中,安全过滤器链充当了外观角色,它封装了一系列的安全处理步骤,提供了一个简单的接口供开发者配置和使用。通过引入安全过滤器链外观,开发者可以方便地实现各种安全功能,而无需深入了解每个安全处理步骤的实现。
Spring Integration(集成框架): Spring Integration是Spring框架的一个扩展模块,用于处理各种不同系统之间的集成问题。在Spring Integration中,集成通道充当了外观角色,它封装了消息通道、消息处理器等组件,提供了一个简单的接口供开发者使用。通过引入集成通道外观,开发者可以更容易地实现系统集成,而无需关心底层的集成细节。
图形示例
步骤 1: 创建图形一个接口。
java
public interface Shape {
void draw();
}
步骤 2: 创建实现相同接口的具体类。
java
public class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("图形:矩形");
}
}
java
public class Circle implements Shape{
@Override
public void draw() {
System.out.println("图形:圆形");
}
}
步骤 3: 创建外观类
java
public class ShapeMaker {
private Shape circle;
private Shape rectangle;
private Shape square;
public ShapeMaker() {
circle = new Circle();
rectangle = new Rectangle();
square = new Square();
}
public void drawCircle(){
circle.draw();
}
public void drawRectangle(){
rectangle.draw();
}
public void drawSquare(){
square.draw();
}
}
步骤 4: 使用外观类绘制各种类型的形状。
java
public class FacadePatternDemo {
public static void main(String[] args) {
ShapeMaker shapeMaker = new ShapeMaker();
shapeMaker.drawCircle();
shapeMaker.drawRectangle();
shapeMaker.drawSquare();
}
}
在这个示例中,我们有一个 Shape 接口,以及实现该接口的具体形状类(Rectangle、Square、Circle)。然后,我们创建了一个外观类 ShapeMaker,该类封装了对这些具体形状类的调用。最后,在 FacadePatternDemo 类中,我们使用 ShapeMaker 类来绘制各种类型的形状。
这种设计模式的优势在于客户端无需了解每个具体形状类的实现细节,而是通过简单的接口调用来实现相应的功能。外观模式在提供清晰简洁的API的同时,也降低了客户端与子系统之间的耦合度。
代码地址
23种设计模式相关代码后续会逐步提交到github上,方便学习,欢迎指点:
代码地址