笔头云 笔头云
首页
设计模式
SQL教程
Redis
归档
关于
友链

笔头云

非淡泊无以明志,非宁静无以致远。
首页
设计模式
SQL教程
Redis
归档
关于
友链
  • 设计原则
  • 设计模式
  • 单例模式
  • 工厂模式
  • 建造者模式
  • 原型模式
  • 适配器模式
  • 代理模式
  • 装饰器模式
  • 门面模式
    • 定义
    • 结构
    • 优点
    • 缺点
    • 应用场景
    • 解决的问题
    • 示例代码1
    • 示例代码2
    • 常见问题
  • 桥接模式
  • 享元模式
  • 组合模式
  • 策略模式
  • 模板方法模式
  • 观察者模式
  • 责任链模式
  • 状态模式
  • 迭代器模式
  • 访问者模式
  • 中介模式
  • 命令模式
  • 解释器模式
  • 备忘录模式
  • 设计模式
笔头云
2023-11-08
目录

门面模式

# 门面模式

# 定义

为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
在门面模式中,存在一个称为门面的类,它封装了一组子系统的功能。门面类充当了客户端和子系统之间的中间层,简化了客户端与子系统之间的交互。客户端只需要与门面类进行交互,而不需要直接与子系统的组件进行通信。

# 结构

门面(Facade):门面是门面模式的核心角色,它提供了一个简化的接口,用于访问子系统的功能。门面封装了子系统的复杂性,将客户端的请求转发给适当的子系统组件。
子系统(Subsystems):子系统是实际执行功能的组件集合。它们包含了复杂的逻辑和操作,但对于客户端来说是不可见的。门面通过与子系统进行交互来完成客户端的请求。

门面模式

门面模式

- img: https://bitouyun.com/images/design-pattern/facade.png
  link: https://bitouyun.com/images/design-pattern/facade.png
  name: 门面模式
- img: https://bitouyun.com/images/design-pattern/facade2.png
  link: https://bitouyun.com/images/design-pattern/facade2.png
  name: 门面模式
1
2
3
4
5
6

# 优点

简化客户端代码:门面模式提供了一个简化的接口,隐藏了子系统的复杂性,从而简化了客户端的代码。客户端只需要与门面进行交互,而不需要了解子系统的内部实现细节。
解耦客户端和子系统:门面模式将客户端与子系统之间进行了解耦。客户端只与门面进行交互,对于子系统的变化是透明的。这样可以提高系统的灵活性和可维护性。
提供高层接口:门面类可以根据客户端的需求,组合和调用子系统的功能,从而提供更高层次的接口。这样可以简化客户端的操作,并且可以更好地组织和管理子系统的功能。
隐藏复杂性:门面模式通过将复杂性封装在门面内部,使得客户端只需要关注简化的接口。这可以降低开发过程中的认知负担,并提高代码的可读性。

# 缺点

违反开闭原则:当需要添加新的功能或修改现有功能时,可能需要修改门面类。这可能会导致门面类的变得庞大,并且需要修改客户端代码。
增加了系统的复杂性:引入门面模式会增加一个额外的抽象层,这可能会增加系统的复杂性。过度使用门面模式可能导致系统变得过于复杂和难以理解。
灵活和高效性:门面模式适用于需要隐藏复杂子系统的情况,但并不适用于所有场景。在某些情况下,直接与子系统进行交互可能更加灵活和高效。

# 应用场景

简化复杂子系统:当存在一个复杂的子系统,其中包含多个组件或服务,并且客户端需要与这些组件进行交互时,门面模式可以提供一个简化的接口,将子系统的复杂性隐藏起来。这样可以降低客户端代码的复杂性,并提供一个更易于使用的接口。
提供统一的接口:当需要将多个相关的子系统组合起来,为客户端提供一个统一的接口时,可以使用门面模式。门面类可以根据客户端的需求,调用适当的子系统组件,并组合其功能。这样可以简化客户端的操作,并提供更高层次的接口。
封装遗留系统:当存在一个遗留系统,其中的代码结构较为混乱且难以理解时,可以引入门面模式来封装该系统。门面模式可以提供一个清晰的接口层,隐藏底层系统的复杂性和混乱的代码结构。这样可以帮助团队更好地组织和维护遗留系统。
松耦合子系统和客户端:门面模式可以将客户端代码与子系统解耦,使得客户端不需要直接依赖于子系统的具体实现。这样可以提高系统的灵活性和可维护性,使得子系统的变化对客户端来说是透明的。

# 解决的问题

解决易用性问题:门面模式可以用来封装系统的底层实现,隐藏系统的复杂性,提供一组更加简单易用、更高层的接口。
解决性能问题: 前端和服务器之间是通过网络通信的,网络通信耗时比较多,为了提高响应速度,我们要尽量减少前端与服务器之间的网络通信次数。我们可以将多个接口的数放入一个门面接口中。
解决分布式事务问题:将多个接口的调用放入一个门面接口中,并使用事务来控制。

# 示例代码1

场景1

文件系统的访问会涉及多个底层操作,如打开文件、读取、写入、关闭等。通过门面模式封装这些底层操作的复杂性,提供一个简单的接口供客户端进行文件操作。

    /**
     * 文件子系统
     */
    @Slf4j
    public class FileSystem {
      public void openFile(String fileName) {
        log.info("打开文件:{}", fileName);
      }
    
      public void readFile(String fileName) {
        log.info("读取文件:{}", fileName);
      }
    
      public void writeFile(String fileName) {
        log.info("写入文件:{}", fileName);
      }
    
      public void closeFile(String fileName) {
        log.info("关闭文件:{}", fileName);
      }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    /**
     * 文件系统门面
     * 封装文件系统访问的复杂性
     */
    public class FileSystemFacade {
    
      private FileSystem fileSystem;
    
      public FileSystemFacade(FileSystem fileSystem) {
        this.fileSystem = fileSystem;
      }
    
      // 读取文件
      public void readFile(String fileName) {
        fileSystem.openFile(fileName);
        fileSystem.readFile(fileName);
        fileSystem.closeFile(fileName);
      }
    
      // 写入文件
      public void writeFile(String fileName) {
        fileSystem.openFile(fileName);
        fileSystem.writeFile(fileName);
        fileSystem.closeFile(fileName);
      }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    /**
     * 测试类
     * 通过门面类FileSystemFacade提供的简化接口进行读取和写入操作
     */
    public class Client {
      public static void main(String[] args) {
        FileSystem fileSystem = new FileSystem();
        FileSystemFacade facade = new FileSystemFacade(fileSystem);
        facade.readFile("读取门面模式.txt");
        facade.writeFile("写入门面模式.txt");
      }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    // Make sure to add code blocks to your code group

    # 示例代码2

    场景2

    客户端通过门面模式调用不同子系统的业务

      /**
       * 门面类
       * 提供客户端访问接口
       */
      public class Facade {
        // 业务系统 
        private SystemA systemA;
        private SystemB systemB;
        private SystemC systemC;
      
        public Facade(SystemA systemA, SystemB systemB, SystemC systemC) {
          this.systemA = systemA;
          this.systemB = systemB;
          this.systemC = systemC;
        }
        // 业务A
        public void doSomethingA() {
          systemA.doSomethingA();
        }
        // 业务B
        public void doSomethingB() {
          systemB.doSomethingB();
        }
        // 业务C
        public void doSomethingC() {
          systemC.doSomethingC();
        }
      }
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      /**
       * 子系统A
       */
      @Slf4j
      public class SystemA {
      
        public void doSomethingA() {
          log.info("子系统A执行业务逻辑A");
        }
      }
      
      /**
       * 子系统B
       */
      @Slf4j
      public class SystemB {
      
        public void doSomethingB() {
          log.info("子系统B执行业务逻辑B");
        }
      }
      
      /**
       * 子系统A
       */
      @Slf4j
      public class SystemC {
      
        public void doSomethingC() {
          log.info("子系统C执行业务逻辑C");
        }
      }
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      /**
       * 测试类
       */
      public class Client {
      
        public static void main(String[] args) {
          // 子系统对象
          SystemA systemA = new SystemA();
          SystemB systemB = new SystemB();
          SystemC systemC = new SystemC();
          // 门面对象
          Facade facade = new Facade(systemA, systemB, systemC);
          facade.doSomethingA();
          facade.doSomethingB();
          facade.doSomethingC();
        }
      }
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      // Make sure to add code blocks to your code group

      # 常见问题

      一个子系统可以有多少个门面?

      一般情况下,一个子系统有一个门面就足够,如果门面类庞大到不能忍受的程度可以拆分成多个门面;
      调用子系统的客户端有不同的权限,不能共用统一的门面时,可以新建一个门面,在新建的门面中引用原有的门面,对外提供统一的子系统方法。

      门面接口能参与子系统的业务逻辑吗?

      门面接口中不能参与子系统的业务逻辑,如果参与业务逻辑会引发一个倒依赖的问题,对外提供的业务必须依赖门面接口,让子系统依赖门面接口才能实现某个功能,是一个设计上的错误,破坏了系统的封装性。可以通过新建一个类或方法封装完后提供给门面类。

      #结构型模式#设计模式
      上次更新: 2023/11/17, 09:38:49
      装饰器模式
      桥接模式

      ← 装饰器模式 桥接模式→

      最近更新
      01
      FRP内网穿透docker部署 工具
      05-07
      02
      Office Util办公工具 工具
      01-14
      03
      Git常用命令
      01-16
      更多文章>
      Theme by Vdoing | Copyright © 2023-2025 鲁ICP备2023014898号 公安备案号:37020302372159
      • 跟随系统
      • 浅色模式
      • 深色模式
      • 阅读模式
      ×