门面模式【Facade Pattern】,什么是门面模式?核心概念?主要角色?优缺点?应用场景?门面模式实现?

目录


设计模式专栏目录(点击进入…)



什么是门面模式?

门面模式(Facade Pattern)是一种结构型设计模式,它为一个复杂的子系统提供了一个简化的接口。通过这个接口,客户端可以更方便地与子系统进行交互,而不必直接面对子系统内部的复杂性。门面模式的核心思想是隐藏系统的复杂性,提供一个统一且简化的接口,从而降低客户端的使用难度。


门面模式核心概念

(1)简化接口

门面模式提供了一个简单的接口,屏蔽了复杂的子系统,实现了对外提供统一、简单的调用方式。

(2)解耦客户端与子系统

通过使用门面,客户端不需要了解系统内部的细节。这样一来,客户端与子系统的耦合度降低,修改子系统不会影响客户端。

(3)分离关注点

客户端只需通过门面与系统交互,不需要关心系统的具体实现,降低了代码的复杂性。


门面模式主要角色

(1)门面角色(Facade)

对外的统一接口,用来整合多个子接口。

(2)子系统角色(SubSystem)

客户端真正需要访问的接口,被Facade整合,客户端并不知道该接口的存在。


门面模式优缺点

优点

(1)简化复杂系统的接口

门面模式通过提供一个简单、统一的接口来简化客户端与复杂系统的交互。客户端不需要了解系统内部的复杂实现,极大地降低了使用难度。

(2)松散耦合

门面模式将客户端与系统的具体实现隔离开来,减少了它们之间的依赖。子系统的内部变化不会直接影响客户端,只需修改门面类即可应对系统内部的改变。

(3)更好的层次化结构

门面模式有助于分离系统中的不同层次,形成清晰的层次结构。通过引入门面,可以有效组织和管理子系统之间的复杂关系,保证系统的可维护性和可扩展性。

(4)代码可读性和维护性提高

门面模式让复杂系统的使用变得更清晰,简化了系统的使用逻辑,增强了代码的可读性和维护性。

(5)兼容单一职责原则

门面类通常只负责简化接口,而不会影响子系统的职责分工。门面类是对外提供统一服务的入口,确保各个子系统依然各司其职。

缺点

(1)隐藏了系统的部分功能

由于门面模式简化了接口,某些子系统的高级功能可能无法通过门面暴露给客户端。如果客户端需要访问子系统的更多细节,门面可能无法提供足够的灵活性。

(2)可能引入不必要的复杂性

在某些情况下,门面类可能变得过于臃肿,承担了过多的职责。如果门面类的功能不断增加,可能违背“单一职责原则”,反而让系统变得更加复杂。

(3)性能开销

门面模式会引入一个额外的中间层,这个中间层在某些性能敏感的系统中可能引起额外的性能开销。

(4)可能掩盖问题

门面模式会屏蔽底层的复杂性,但也可能掩盖底层子系统中的设计问题。客户端不直接接触底层系统,有时可能导致系统潜在的问题不易被发现。


门面模式应用场景

门面模式(Facade Pattern)适用于简化系统与客户端交互的场景,特别是在复杂子系统或需要隐藏内部实现细节的情况下。

(1)简化复杂系统的使用

如果一个系统由多个子系统组成,并且这些子系统之间的交互逻辑复杂,那么可以使用门面模式为这些子系统提供一个统一的入口。这样,客户端只需与门面交互,而不必处理各个子系统的具体实现。

示例:大型软件系统中的模块(如财务、用户管理、库存等)可以通过门面统一管理。

(2)为旧系统提供兼容接口

当要对现有系统进行升级或重构时,使用门面模式可以为旧系统提供一个新接口,隐藏旧系统的复杂性,同时为新功能提供扩展。这有助于在不破坏旧代码的前提下引入新功能。

示例:软件系统的版本更新时,使用门面模式为旧版本提供兼容接口,同时逐步扩展新功能。

(3)分层开发系统

在分层结构的软件开发中,每一层通常都需要提供接口与上层交互。可以使用门面模式为每一层提供简化的接口,确保上层只需通过该门面层来访问下层的服务,而不需要关心下层的实现细节。

示例:典型的三层架构(表现层、业务逻辑层、数据访问层)中,业务逻辑层可以通过门面模式向表现层提供统一的访问接口。

(4)构建库或框架时

当开发一个库或者框架时,为了让外部用户能够方便使用库的功能,可以通过门面模式提供一个简单易用的接口,屏蔽内部实现的复杂性。这样库的使用者可以通过这个接口调用内部功能,而不必了解具体的细节。

示例:在图形处理、网络通信或数据库操作的库中,开发者可以提供一个简化的门面,来对外提供服务。

(5)减少客户端与多个子系统之间的依赖

在一些情况下,客户端可能需要与多个子系统打交道,这会增加系统的复杂性和耦合性。使用门面模式可以减少客户端与子系统之间的直接依赖,通过门面类统一与各个子系统的交互。

示例:一个电商平台的支付系统可能涉及订单管理、库存管理、支付网关等多个子系统。可以通过门面模式来协调这些子系统的交互。

(6)跨平台应用开发

如果系统需要支持多平台(如桌面应用、移动端、Web 应用),每个平台的功能可能有所不同,接口也会有所不同。门面模式可以提供一个统一的接口,使得跨平台开发更为简单和统一。

示例:跨平台的游戏引擎、GUI 库等,通常为不同平台提供统一的编程接口。

(7)防止客户端对复杂子系统的直接依赖

在某些情况下,我们希望系统的某些复杂部分对外部隐藏,比如底层的硬件调用、复杂的算法库、或第三方服务。通过门面模式,客户端可以在不依赖复杂子系统的情况下实现对功能的使用,这也增强了系统的可扩展性和维护性。

示例:在嵌入式系统或硬件驱动开发中,可以通过门面模式隐藏复杂的硬件操作,提供简化的应用接口。

(8)创建事务管理和工作流引擎

在复杂的事务处理和工作流管理中,往往涉及多个步骤和子系统的协调。通过门面模式,可以将这些流程进行封装,统一对外暴露一个接口,确保工作流各个步骤的有序执行,简化了使用者的操作流程。

示例:银行系统的转账流程可能涉及验证账户、冻结资金、执行转账、生成报告等步骤,门面可以统一这些操作。


门面模式实现

大家都写过纸质的信件吧
比如:给女朋友写情书什么的,写信的过程大家都还记得吧,先写信的内容,然后写信封,然后把信放到信封中,封好,投递到信箱中进行邮递,这个过程还是比较简单的,虽然简单,这四个步骤都是要跑的呀,信多了还是麻烦。

比如:到了情人节,为了大海捞针,给十个女孩子发情书,都要这样跑一遍,你不要累死,更别说你要发个广告信啥的,一下子发 1 千万封邮件,那不就完蛋了?那怎么办呢?还好,现在邮局开发了一个新业务,你只要把信件的必要信息高速我,我给你发,我来做这四个过程,你就不要管了,只要把信件交给我就成了。

在这里插入图片描述

1、定义写信的过程接口

package com.uhhe.common.design.facade;

/**
 * 定义一个写信的过程
 *
 * @author nizhihao
 * @version 1.0.0
 * @date 2023/2/27 15:02
 */
public interface LetterProcess {

    /**
     * 首先要写信的内容
     *
     * @param context 内容
     */
    void writeContext(String context);

    /**
     * 其次写信封
     *
     * @param address 地址
     */
    void fillEnvelope(String address);

    /**
     * 把信放到信封里
     */
    void letterIntoEnvelope();

    /**
     * 然后邮递
     */
    void sendLetter();

}

2、写信过程的具体实现

package com.uhhe.common.design.facade;

/**
 * 写信的具体实现
 *
 * @author nizhihao
 * @version 1.0.0
 * @date 2023/2/27 15:03
 */
public class LetterProcessImpl implements LetterProcess {

    @Override
    public void writeContext(String context) {
        System.out.println("填写信的内容..." + context);
    }

    @Override
    public void fillEnvelope(String address) {
        System.out.println("填写收件人地址及姓名..." + address);
    }

    @Override
    public void letterIntoEnvelope() {
        System.out.println("把信放到信封中...");
    }

    @Override
    public void sendLetter() {
        System.out.println("邮递信件...");
    }

}

3、增加了一个门面

这个类是什么意思呢,就是说现在又一个叫 Hell Road PostOffice(地狱路邮局)提供了一种新型的
服务,客户只要把信的内容以及收信地址给他们,他们就会把信写好,封好,并发送出去,这种服务提出时大受欢迎呀,这简单呀,客户减少了很多工作。

package com.uhhe.common.design.facade;

/**
 * 写信发送邮递一体化
 *
 * @author nizhihao
 * @version 1.0.0
 * @date 2023/2/27 15:00
 */
public class ModemPostOffice {

    private final LetterProcess letterProcess = new LetterProcessImpl();

    /**
     * 写信,封装,投递,一体化了
     *
     * @param context 内容
     * @param address 地址
     */
    public void sendLetter(String context, String address) {
        // 写信
        letterProcess.writeContext(context);
        // 写好信封
        letterProcess.fillEnvelope(address);
        // 把信放到信封中
        letterProcess.letterIntoEnvelope();
        // 邮递信件
        letterProcess.sendLetter();
    }

}

提供这种模式后,系统的扩展性也有了很大的提高,突然一个非常时期,寄往 God Province(上帝省)的邮件都必须进行安全检查,那我们这个就很好处理了

package com.uhhe.common.design.facade;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * 警察检查
 *
 * @author nizhihao
 * @version 1.0.0
 * @date 2023/2/27 15:00
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Police {

    public void checkLetter(LetterProcess letterProcess) {
        System.out.println("检查信件...");
    }

}
package com.uhhe.common.design.facade;

/**
 * 写信发送邮递一体化
 *
 * @author nizhihao
 * @version 1.0.0
 * @date 2023/2/27 15:00
 */
public class ModemPostOffice {

    private final LetterProcess letterProcess = new LetterProcessImpl();
    private final Police letterPolice = new Police();

    /**
     * 写信,封装,投递,一体化了
     *
     * @param context 内容
     * @param address 地址
     */
    public void sendLetter(String context, String address) {
        // 写信
        letterProcess.writeContext(context);
        // 写好信封
        letterProcess.fillEnvelope(address);
        //警察要检查信件了
        letterPolice.checkLetter(letterProcess);
        // 把信放到信封中
        letterProcess.letterIntoEnvelope();
        // 邮递信件
        letterProcess.sendLetter();
    }

}

4、门面模式使用

package com.uhhe.common.design.facade;

/**
 * 门面模式使用
 * 
 * @author nizhihao
 * @version 1.0.0
 * @date 2023/2/27 15:07
 */
public class Client {

    /**
     * 门面模式【Facade Pattern】:
     * <p>
     * 大家都是高智商的人,都写过纸质的信件吧,比如:给女朋友写情书什么的,写信的过程大家都还记得吧
     * 先写信的内容,然后写信封,然后把信放到信封中,封好,投递到信箱中进行邮递,这个过程还是比较简单的
     * 虽然简单,这四个步骤都是要跑的呀,信多了还是麻烦,比如到了情人节,为了大海捞针,给十个女孩子发情书,都要这样跑一遍,
     * 你不要累死,更别说你要发个广告信啥的,一下子发 1 千万封邮件,那不就完蛋了?
     * 那怎么办呢?
     * 还好,现在邮局开发了一个新业务,你只要把信件的必要信息告诉我,我给你发,我来做这四个过程,你就不要管了,只要把信件交给我就成了
     * <p>
     * 提供这种模式后,系统的扩展性也有了很大的提高,突然一个非常时期,
     * 寄往 God Province(上帝省)的邮件都必须进行安全检查,那我们这个就很好处理了
     * <p>
     * 门面模式是一个很好的封装方法,一个子系统比较复杂的实话,比如算法或者业务比较复杂,就可以封装出一个或多个门面出来
     * 项目的结构简单,而且扩展性非常好。还有,在一个较大项目中的时候,为了避免人员带来的风险,也可以使用这个模式,
     * 技术水平比较差的成员,尽量安排独立的模块(Sub System),然后把他写的程序封装到一个门面里,尽量让其他项目成员不用看到这些烂人的代码,看也看不懂
     * <p>
     * 也遇到过一个“高人”写的代码, private 方法、构造函数、常量基本都不用,
     * 你要一个 public 方法,好,一个类里就一个 public 方法,所有代码都在里面,然后你就看吧,一大坨的程序,看着
     * 能把人逼疯,使用门面模式后,对门面进行单元测试,约束项目成员的代码质量,对项目整体质量的提升也是一个比较好的帮助
     */
    public static void main(String[] args) {
        // 现代化的邮局,有这项服务,邮局名称叫Hell Road
        ModemPostOffice hellRoadPostOffice = new ModemPostOffice();

        // 只要把信的内容和收信人地址给他,他会帮你完成一系列的工作;
        // 定义一个地址
        String address = "Happy Road No. 666,God Province,Heaven";
        String context = "Hello,It's me,do you know who I am? I'm your old lover. I'd like to....";
        hellRoadPostOffice.sendLetter(context, address);
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

未禾

您的支持是我最宝贵的财富!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值