设计模式之门面模式(外观模式)的原理、组成
笔记哥 /
04-22 /
6点赞 /
0评论 /
576阅读
# 门面模式(外观模式)
## 模式定义
- **门面模式**(`Facade Pattern`)也叫做**外观模式**,是一种**结构型设计模式**。
> 它提供一个**统一的接口**,封装了一个或多个子系统的复杂功能,并向客户端提供一个**简单的调用方式**。
>
> 通过引入**门面**,**客户端**无需直接与**子系统**交互,而只需要通过**门面**来与**子系统**进行通信。
## 模式的组成
- **门面**(`Facade`):门面角色是门面模式的核心,它封装了系统内部复杂子系统的接口,为客户端提供一个简单的高层接口。门面角色知道哪些子系统负责处理请求,并将请求转发给相应的子系统进行处理。
- **子系统**(`Subsystem`):子系统角色是实际执行系统功能的组件。每个子系统都有自己的职责和行为,通过门面角色对外提供服务。
- **客户端**(`Client`):客户端角色通过调用门面角色提供的高层接口来使用系统功能,而无需直接与子系统交互。
>
>
> 在**门面模式**中,**门面角色**充当了**客户端**和**子系统**之间的**中介者**,**隐藏了子系统的复杂性**,**简化了客户端的调用过程**。
>
> **客户端**只需要与**门面角色**进行交互,而不需要了解和处理**子系统的具体细节**。
>
- 【特别注意】
>
> - **门面对象**只是提供一个**访问子系统的一个路径**而已,它不应该也不能参与具体的业务逻辑;
> - 否则,就会产生一个**倒依赖**的问题:**子系统**必须**依赖门面**才能被访问,这是设计上一个**严重错误**,不仅会违反了**单一职责原则**,同时也破坏了**系统的封装性**。
>
>
## 适用场景
- 当一个系统有很多复杂的子系统时,可以使用**门面模式**将其封装起来,**隐藏内部复杂性**,简化客户端的调用。
- 当需要将**客户端**与**复杂的子系统**做**解耦**,降低系统之间的依赖时,可以使用**门面模式**。
## 模式特点
### 优点
- 简化客户端的调用过程,**隐藏了子系统的复杂性**,提供了一个统一的接口,客户端无需了解子系统的具体实现。
- 减少系统的相互依赖,**解耦**了客户端与子系统之间的依赖关系。
- 提高了代码的**可维护性和可读性**。
### 缺点
- 门面模式可能会导致**门面类变得庞大**,**承担过多的责任**。
- 如果需要**修改子系统的功能**,可能需要**修改门面类**。
## 门面模式的优化
>
>
> 在实际应用中,我们可以对门面模式进行一些优化和扩展。以下是几个常见的优化实现方式:
>
### 子系统解耦
- **门面类**可以通过**委托**来**调用子系统**的功能,而不是**直接依赖**于**具体的子系统**。
>
>
> 这样可以使得**子系统**能够**独立演化**,不受**门面类**的影响。
>
```csharp
// 门面类
class Facade {
private SubSystemInterface subSystemA;
private SubSystemInterface subSystemB;
public Facade() {
subSystemA = new ConcreteSubSystemA();
subSystemB = new ConcreteSubSystemB();
}
// 提供给客户端的接口
public void operation() {
subSystemA.operation();
subSystemB.operation();
}
}
// 子系统接口
interface SubSystemInterface {
void operation();
}
// 具体的子系统A
class ConcreteSubSystemA implements SubSystemInterface {
public void operation() {
// 实现具体的功能
}
}
// 具体的子系统B
class ConcreteSubSystemB implements SubSystemInterface {
public void operation() {
// 实现具体的功能
}
}
```
### 多个门面类
- 当**门面**已经**庞大到不能忍受的程度**,**承担过多的责任**时,可以考虑使用**多个门面类**。
- **每个门面类**负责与**特定的子系统**交互,原则上建议**按照功能拆分**
>
>
>
> >
> >
> > 比如,一个数据库操作的门面可以拆分为查询门面、删除门面、更新门面等。
> >
>
>
```csharp
// 子系统A的门面类
class SubSystemAFacade {
private SubSystemA subSystemA;
public SubSystemAFacade() {
subSystemA = new SubSystemA();
}
// 提供给客户端的接口
public void operation() {
subSystemA.operationA();
}
}
// 子系统B的门面类
class SubSystemBFacade {
private SubSystemB subSystemB;
public SubSystemBFacade() {
subSystemB = new SubSystemB();
}
// 提供给客户端的接口
public void operation() {
subSystemB.operationB();
}
}
```
>
>
> 通过上述优化实现方式,我们能够灵活地应对不同的需求和场景,提高了系统的可扩展性和维护性。
>
### 门面嵌套
- 假设我们有一个**文件处理系统**,其中包括3个子系统:
>
>
> 文件读取(FileReader)、文件写入(FileWriter)和文件压缩(FileCompressor)。
>
- 现在有2个模块来访问该子系统:
>
> - **通用模块**(GeneralModule)可以完整地访问所有业务逻辑,而**受限模块**(RestrictedModule)只能访问文件读取操作。
>
>
- 在这种情况下,我们可以在**门面**外再**嵌套门面**来解决**接口权限问题**,以供不同的模块访问。
```csharp
// 子系统:文件读取
class FileReader {
public void read(String filePath) {
System.out.println("读取文件:" + filePath);
// 具体的读取逻辑...
}
}
// 子系统:文件写入
class FileWriter {
public void write(String filePath, String content) {
System.out.println("写入文件:" + filePath);
// 具体的写入逻辑...
}
}
// 子系统:文件压缩
class FileCompressor {
public void compress(String filePath, String destinationPath) {
System.out.println("压缩文件:" + filePath + " -> " + destinationPath);
// 具体的压缩逻辑...
}
}
// 通用模块门面
class GeneralFacade {
private FileReader fileReader;
private FileWriter fileWriter;
private FileCompressor fileCompressor;
public GeneralFacade() {
this.fileReader = new FileReader();
this.fileWriter = new FileWriter();
this.fileCompressor = new FileCompressor();
}
public void processFile(String filePath, String content, String destinationPath) {
fileReader.read(filePath);
fileWriter.write(filePath, content);
fileCompressor.compress(filePath, destinationPath);
}
public void read(String filePath) {
fileReader.read(filePath);
}
}
// 受限模块门面
class RestrictedFacade {
private GeneralFacade generalFacade = new GeneralFacade();
public void readRestrictedFile(String filePath) {
generalFacade.read(filePath);
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
GeneralFacade generalFacade = new GeneralFacade();
generalFacade.processFile("file.txt", "Hello World!", "compressed.zip");
RestrictedFacade restrictedFacade = new RestrictedFacade();
restrictedFacade.readRestrictedFile("file.txt");
}
}
```
- 在上述示例中,我们使用了2个**不同的门面**:`GeneralFacade`和`RestrictedFacade`。
>
> - `GeneralFacade`提供了**完整的访问子系统的方法**(`processFile`)
> - 而`RestrictedFacade`仅提供了**受限的文件读取方法**(`readRestrictedFile`)
>
>
>
>
> 通过**不同的门面对象**,**通用模块**可以访问所有子系统功能,而**受限模块**只能访问特定的子系统功能。
>
# 案例实践
## CASE 门面模式的简单实现
### SubSystemA / SubSystemB
- 子系统A
```csharp
// 子系统A
public class SubSystemA {
public void operationA() {
System.out.println("子系统A的操作");
}
}
```
- 子系统B
```csharp
public class SubSystemB {
public void operationB() {
System.out.println("子系统B的操作");
}
}
```
- 子系统C
```csharp
public class SubSystemC {
public void operationC() {
System.out.println("子系统C的操作");
}
}
```
### Facade/门面类
```csharp
public class Facade {
private SubSystemA subSystemA;
private SubSystemB subSystemB;
private SubSystemC subSystemC;
public Facade() {
subSystemA = new SubSystemA();
subSystemB = new SubSystemB();
subSystemC = new SubSystemC();
}
// 提供简单的接口给客户端调用,隐藏了子系统的复杂性
public void operation() {
subSystemA.operationA();
subSystemB.operationB();
subSystemC.operationC();
}
}
```
## CASE 电商系统
- 场景描述:
>
>
> 假设我们的**电子商务系统**包含了**订单管理**、**库存管理**和**支付管理**等子系统。
>
> 为了**简化客户端的调用过程**,我们可以使用**门面模式**来封装这些子系统,并提供一个统一的接口。
>
### OrderService/订单管理子系统
```csharp
// 订单管理子系统
class OrderService {
public void createOrder() {
// 创建订单的具体实现
}
}
```
### InventoryService/库存管理子系统
```csharp
// 库存管理子系统
class InventoryService {
public void checkStock() {
// 检查库存的具体实现
}
}
```
### PaymentService/支付管理子系统
```csharp
// 支付管理子系统
class PaymentService {
public void makePayment() {
// 支付的具体实现
}
}
```
### ECommerceFacade/电子商务门面类
```csharp
// 电子商务门面类
class ECommerceFacade {
private OrderService orderService;
private InventoryService inventoryService;
private PaymentService paymentService;
public ECommerceFacade() {
orderService = new OrderService();
inventoryService = new InventoryService();
paymentService = new PaymentService();
}
// 提供给客户端的接口
public void placeOrder() {
orderService.createOrder();
inventoryService.checkStock();
paymentService.makePayment();
}
}
```
- 我们创建了一个**电子商务门面类**(ECommerceFacade),它封装了订单管理、库存管理和支付管理等子系统,并提供了一个**简单的接口**(`placeOrder`)供客户端调用。
>
>
> 这样,客户端只需要通过门面类来完成下单操作,而无需直接与子系统交互。
>
## CASE Shape(形状接口) 与 ShapeMaker(形状创建器外观类)
### 场景描述
- 我们将创建一个 `Shape` 接口和实现了 `Shape` 接口的实体类。下一步是定义一个外观类 `ShapeMaker`。
- `ShapeMaker` 类使用实体类来代表用户对这些类的调用。
- `FacadePatternDemo` 类使用 `ShapeMaker` 类来显示结果。

### Shape :抽象接口
```csharp
public interface Shape {
void draw();
}
```
### Rectangle / Square :具体的接口实现类(子系统)
- Rectangle
```csharp
public class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("Rectangle::draw()");
}
}
```
- Square
```csharp
public class Square implements Shape {
@Override
public void draw() {
System.out.println("Square::draw()");
}
}
```
- Circle
```csharp
public class Circle implements Shape {
@Override
public void draw() {
System.out.println("Circle::draw()");
}
}
```
### ShapeMaker(外观类)
```csharp
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();
}
}
```
### FacadePatternDemo
- 使用该外观类画出各种类型的形状。
```csharp
public class FacadePatternDemo {
public static void main(String[] args) {
ShapeMaker shapeMaker = new ShapeMaker();
shapeMaker.drawCircle();
shapeMaker.drawRectangle();
shapeMaker.drawSquare();
}
}
```
>
>
> out
>
```csharp
Circle::draw()
Rectangle::draw()
Square::draw()
```
本文来自投稿,不代表本站立场,如若转载,请注明出处:http//www.knowhub.vip/share/2/2479
- 热门的技术博文分享
- 1 . ESP实现Web服务器
- 2 . 从零到一:打造高效的金仓社区 API 集成到 MCP 服务方案
- 3 . 使用C#构建一个同时问多个LLM并总结的小工具
- 4 . .NET 原生驾驭 AI 新基建实战系列Milvus ── 大规模 AI 应用的向量数据库首选
- 5 . 在Avalonia/C#中使用依赖注入过程记录
- 6 . [设计模式/Java] 设计模式之工厂方法模式
- 7 . 5. RabbitMQ 消息队列中 Exchanges(交换机) 的详细说明
- 8 . SQL 中的各种连接 JOIN 的区别总结!
- 9 . JavaScript 中防抖和节流的多种实现方式及应用场景
- 10 . SaltStack 远程命令执行中文乱码问题
- 11 . 推荐10个 DeepSeek 神级提示词,建议搜藏起来使用
- 12 . C#基础:枚举、数组、类型、函数等解析
- 13 . VMware平台的Ubuntu部署完全分布式Hadoop环境
- 14 . C# 多项目打包时如何将项目引用转为包依赖
- 15 . Chrome 135 版本开发者工具(DevTools)更新内容
- 16 . 从零创建npm依赖,只需执行一条命令
- 17 . 关于 Newtonsoft.Json 和 System.Text.Json 混用导致的的序列化不识别的问题
- 18 . 大模型微调实战之训练数据集准备的艺术与科学
- 19 . Windows快速安装MongoDB之Mongo实战
- 20 . 探索 C# 14 新功能:实用特性为编程带来便利
- 相关联分享
- [设计模式/Java] 设计模式之工厂方法模式
- 【对称加密】DES与AES算法详解及Java实现
- 历数Java虚拟机垃圾回收GC收集器的缺点剖析
- Java虚拟机代码是如何一步一步变复杂且难以理解的?
- 产品中不同客户端请求下的 IP 归属地分析方法
- 在java中为什么重写equals一定也要重写hashCode方法?
- 设计模式脉络之软件可扩展性与设计模式
- 设计模式之门面模式(外观模式)的原理、组成
- Java中如何优雅的处理日期
- 学习设计模式有这两就够了:手册+实战项目
- 启用 Java AOT 编译打包 Solon 项目(Solon AOT)
- YtyMark-java 富文本编辑器分享(以开源)
- Java 21新特性有哪些?
- Excel 高性能导出方案推荐(JAVA)
- Spring 中@Autowired,@Resource,@Inject 注解实现原理
- Java AI(智能体)编排开发就用 Solon Flow
- JAVA 24 环境安装与配置教程
- File与IO流之字节流