写点什么

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

作者:码农BookSea
  • 2024-02-19
    浙江
  • 本文字数:4248 字

    阅读完需:约 14 分钟

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

本文已收录至 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)供客户端调用。这样,客户端只需要通过门面类来完成下单操作,而无需直接与子系统交互。

门面模式实现

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


// 子系统Apublic class SubSystemA {    public void operationA() {        System.out.println("子系统A的操作");    }}
// 子系统Bpublic class SubSystemB { public void operationB() { System.out.println("子系统B的操作"); }}
// 子系统Cpublic 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();}
// 具体的子系统Aclass ConcreteSubSystemA implements SubSystemInterface { public void operation() { // 实现具体的功能 }}
// 具体的子系统Bclass 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)。


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

总结

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

发布于: 刚刚阅读数: 7
用户头像

码农BookSea

关注

Java开发工程师 2021-12-26 加入

Java开发菜鸟工程师,写博客的初衷是为了沉淀我所学习,累积我所见闻,分享我所体验。希望和更多的人交流学习。

评论

发布
暂无评论
一文搞懂设计模式—门面模式_Java_码农BookSea_InfoQ写作社区