一文搞懂设计模式—门面模式

2024-02-18 11:44

本文主要是介绍一文搞懂设计模式—门面模式,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

本文已收录至Github,推荐阅读 👉 Java随想录

微信公众号:Java随想录

文章目录

    • 使用场景
    • 门面模式实现
    • 优缺点
    • 门面模式优化
      • 子系统解耦
      • 多个门面类
      • 门面嵌套
    • 总结

软件开发过程中,我们经常会遇到复杂系统,其中包含多个子系统和接口。在这种情况下,为了简化客户端的调用过程,提高代码的可维护性和可读性,我们可以使用门面模式。

门面模式(Facade Pattern)也叫做外观模式,是一种结构型设计模式。它提供一个统一的接口,封装了一个或多个子系统的复杂功能,并向客户端提供一个简单的调用方式。通过引入门面,客户端无需直接与子系统交互,而只需要通过门面来与子系统进行通信。

门面模式中包含以下角色:

  • 门面(Facade):门面角色是门面模式的核心,它封装了系统内部复杂子系统的接口,为客户端提供一个简单的高层接口。门面角色知道哪些子系统负责处理请求,并将请求转发给相应的子系统进行处理。
  • 子系统(Subsystem):子系统角色是实际执行系统功能的组件。每个子系统都有自己的职责和行为,通过门面角色对外提供服务。
  • 客户端(Client):客户端角色通过调用门面角色提供的高层接口来使用系统功能,而无需直接与子系统交互。

在门面模式中,门面角色充当了客户端和子系统之间的中介者,隐藏了子系统的复杂性,简化了客户端的调用过程。客户端只需要与门面角色进行交互,而不需要了解和处理子系统的具体细节。

注意:门面对象只是提供一个访问子系统的一个路径而已,它不应该也不能参与具体的业务逻辑,否则就会产生一个倒依赖的问题:子系统必须依赖门面才能被访问,这是设计上一个严重错误,不仅违反了单一职责原则,同时也破坏了系统的封装性。

使用场景

门面模式适用于以下情况:

  • 当一个系统有很多复杂的子系统时,可以使用门面模式将其封装起来,隐藏内部复杂性,简化客户端的调用。
  • 当需要将客户端与复杂的子系统解耦,降低系统之间的依赖时,可以使用门面模式。

以下是一个简单的示例,展示了门面模式在电子商务系统中的应用。

假设我们的电子商务系统包含了订单管理、库存管理和支付管理等子系统。为了简化客户端的调用过程,我们可以使用门面模式来封装这些子系统,并提供一个统一的接口。

// 订单管理子系统
class OrderService {public void createOrder() {// 创建订单的具体实现}
}// 库存管理子系统
class InventoryService {public void checkStock() {// 检查库存的具体实现}
}// 支付管理子系统
class PaymentService {public void makePayment() {// 支付的具体实现}
}// 电子商务门面类
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)供客户端调用。这样,客户端只需要通过门面类来完成下单操作,而无需直接与子系统交互。

门面模式实现

下面是门面模式的基本结构:

// 子系统A
public class SubSystemA {public void operationA() {System.out.println("子系统A的操作");}
}// 子系统B
public class SubSystemB {public void operationB() {System.out.println("子系统B的操作");}
}// 子系统C
public class SubSystemC {public void operationC() {System.out.println("子系统C的操作");}
}// 门面类
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();}
}

在上述代码中,我们有三个子系统(SubSystemA、SubSystemB、SubSystemC),它们分别实现了具体的功能。然后,我们创建了一个门面类(Facade)来封装这些子系统,并提供了一个简单的接口供客户端调用。

优缺点

优点

  • 简化客户端的调用过程,隐藏了子系统的复杂性,提供了一个统一的接口,客户端无需了解子系统的具体实现。
  • 减少系统的相互依赖,解耦了客户端与子系统之间的依赖关系。
  • 提高了代码的可维护性和可读性。

缺点

  • 门面模式可能会导致门面类变得庞大,承担过多的责任。
  • 如果需要修改子系统的功能,可能需要修改门面类。

门面模式优化

在实际应用中,我们可以对门面模式进行一些优化和扩展。以下是几个常见的优化实现方式:

子系统解耦

门面类可以通过委托来调用子系统的功能,而不是直接依赖于具体的子系统。这样可以使得子系统能够独立演化,不受门面类的影响。

// 门面类
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() {// 实现具体的功能}
}

多个门面类

当门面已经庞大到不能忍受的程度,承担过多的责任时,可以考虑使用多个门面类,每个门面类负责与特定的子系统交互,原则上建议按照功能拆分,比如一个数据库操作的门面可以拆分为查询门面、删除门面、更新门面等。

// 子系统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();}
}

通过上述优化实现方式,我们能够灵活地应对不同的需求和场景,提高了系统的可扩展性和维护性。

门面嵌套

假设我们有一个文件处理系统,其中包括三个子系统:文件读取(FileReader)、文件写入(FileWriter)和文件压缩(FileCompressor)。

现在有两个模块来访问该子系统:通用模块(GeneralModule)可以完整地访问所有业务逻辑,而受限模块(RestrictedModule)只能访问文件读取操作。

在这种情况下,我们可以在门面外再嵌套门面来解决接口权限问题,以供不同的模块访问。

// 子系统:文件读取
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");}
}

在上述示例中,我们使用了两个不同的门面:GeneralFacade和RestrictedFacade。GeneralFacade提供了完整的访问子系统的方法(processFile),而RestrictedFacade仅提供了受限的文件读取方法(readRestrictedFile)。

通过不同的门面对象,通用模块可以访问所有子系统功能,而受限模块只能访问特定的子系统功能。

总结

通过使用门面模式,我们可以简化复杂系统的调用过程,提高代码的可维护性和可读性。门面模式将子系统进行封装,并提供一个简单的接口给客户端,隐藏了子系统的复杂性,同时解耦了客户端与子系统之间的依赖关系。

这篇关于一文搞懂设计模式—门面模式的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/721043

相关文章

【数据结构】——原来排序算法搞懂这些就行,轻松拿捏

前言:快速排序的实现最重要的是找基准值,下面让我们来了解如何实现找基准值 基准值的注释:在快排的过程中,每一次我们要取一个元素作为枢纽值,以这个数字来将序列划分为两部分。 在此我们采用三数取中法,也就是取左端、中间、右端三个数,然后进行排序,将中间数作为枢纽值。 快速排序实现主框架: //快速排序 void QuickSort(int* arr, int left, int rig

在JS中的设计模式的单例模式、策略模式、代理模式、原型模式浅讲

1. 单例模式(Singleton Pattern) 确保一个类只有一个实例,并提供一个全局访问点。 示例代码: class Singleton {constructor() {if (Singleton.instance) {return Singleton.instance;}Singleton.instance = this;this.data = [];}addData(value)

模版方法模式template method

学习笔记,原文链接 https://refactoringguru.cn/design-patterns/template-method 超类中定义了一个算法的框架, 允许子类在不修改结构的情况下重写算法的特定步骤。 上层接口有默认实现的方法和子类需要自己实现的方法

【iOS】MVC模式

MVC模式 MVC模式MVC模式demo MVC模式 MVC模式全称为model(模型)view(视图)controller(控制器),他分为三个不同的层分别负责不同的职责。 View:该层用于存放视图,该层中我们可以对页面及控件进行布局。Model:模型一般都拥有很好的可复用性,在该层中,我们可以统一管理一些数据。Controlller:该层充当一个CPU的功能,即该应用程序

迭代器模式iterator

学习笔记,原文链接 https://refactoringguru.cn/design-patterns/iterator 不暴露集合底层表现形式 (列表、 栈和树等) 的情况下遍历集合中所有的元素

《x86汇编语言:从实模式到保护模式》视频来了

《x86汇编语言:从实模式到保护模式》视频来了 很多朋友留言,说我的专栏《x86汇编语言:从实模式到保护模式》写得很详细,还有的朋友希望我能写得更细,最好是覆盖全书的所有章节。 毕竟我不是作者,只有作者的解读才是最权威的。 当初我学习这本书的时候,只能靠自己摸索,网上搜不到什么好资源。 如果你正在学这本书或者汇编语言,那你有福气了。 本书作者李忠老师,以此书为蓝本,录制了全套视频。 试

利用命令模式构建高效的手游后端架构

在现代手游开发中,后端架构的设计对于支持高并发、快速迭代和复杂游戏逻辑至关重要。命令模式作为一种行为设计模式,可以有效地解耦请求的发起者与接收者,提升系统的可维护性和扩展性。本文将深入探讨如何利用命令模式构建一个强大且灵活的手游后端架构。 1. 命令模式的概念与优势 命令模式通过将请求封装为对象,使得请求的发起者和接收者之间的耦合度降低。这种模式的主要优势包括: 解耦请求发起者与处理者

springboot实战学习(1)(开发模式与环境)

目录 一、实战学习的引言 (1)前后端的大致学习模块 (2)后端 (3)前端 二、开发模式 一、实战学习的引言 (1)前后端的大致学习模块 (2)后端 Validation:做参数校验Mybatis:做数据库的操作Redis:做缓存Junit:单元测试项目部署:springboot项目部署相关的知识 (3)前端 Vite:Vue项目的脚手架Router:路由Pina:状态管理Eleme

状态模式state

学习笔记,原文链接 https://refactoringguru.cn/design-patterns/state 在一个对象的内部状态变化时改变其行为, 使其看上去就像改变了自身所属的类一样。 在状态模式中,player.getState()获取的是player的当前状态,通常是一个实现了状态接口的对象。 onPlay()是状态模式中定义的一个方法,不同状态下(例如“正在播放”、“暂停

软件架构模式:5 分钟阅读

原文: https://orkhanscience.medium.com/software-architecture-patterns-5-mins-read-e9e3c8eb47d2 软件架构模式:5 分钟阅读 当有人潜入软件工程世界时,有一天他需要学习软件架构模式的基础知识。当我刚接触编码时,我不知道从哪里获得简要介绍现有架构模式的资源,这样它就不会太详细和混乱,而是非常抽象和易