「全网最细 + 实战源码案例」设计模式——外观模式

简介: 外观模式(Facade Pattern)是一种结构型设计模式,旨在为复杂的子系统提供一个统一且简化的接口。通过封装多个子系统的复杂性,外观模式使外部调用更加简单、易用。例如,在智能家居系统中,外观类可以同时控制空调、灯光和电视的开关,而用户只需发出一个指令即可。

概念

  • 外观模式是一种结构型模式,为复杂的子系统提供一个统一的接口,使得子系统的功能对外界更加简单、易用。


与真实世界的类比

  • 当你通过打电话给商店下达订单时,接线员就是该商店所有服务和部门的外观。 接线员为你提供了一个包含购物系统、支付网关、送货等服务的简单语言接口


外观模式结构图

// 空调
public class AirCondition {
    public void on() {
        System.out.println("AirCondition is on");
    }

    public void off() {
        System.out.println("AirCondition is off");
    }
}
// 灯
public class Light {

    public void on() {
        System.out.println("Light is on");
    }

    public void off() {
        System.out.println("Light is off");
    }
}
// 电视
public class TV {

    public void on() {
        System.out.println("TV on");
    }

    public void off() {
        System.out.println("TV off");
    }
}
// 外观类,封装了子系统的功能
public class SmartAppliancesFacade {
    private TV tv;
    private AirCondition airCondition;
    private Light light;
    public SmartAppliancesFacade() {
        tv = new TV();
        airCondition = new AirCondition();
        light = new Light();
    }

    public void say(String message){
        if(message.contains("打开")){
            allOn();
        }else if(message.contains("关闭")){
            allOff();
        }else{
            System.out.println("没有这个指令");
        }
    }

    public void allOn() {
        tv.on();
        airCondition.on();
        light.on();
    }

    public void allOff() {
        tv.off();
        airCondition.off();
        light.off();
    }

}
// 客户端类
public class Client {
    public static void main(String[] args) {
        SmartAppliancesFacade facade = new SmartAppliancesFacade();
        facade.say("打开家电");
        System.out.println("-----------------------------------------");

        facade.say("关闭家电");
        System.out.println("-----------------------------------------");

        facade.say("shfsahf");
        System.out.println("-----------------------------------------");
    }
}

适用的应用场景

  • 简化复杂系统:
    • 如果一个系统由多个模块组成,对外提供多个复杂接口,可以通过外观模式提供一个简单的接口调用。
    • 例如:支付系统涉及签名、网络请求、结果处理,通过 Facade Pattern 封装为一个简单的支付接口。
  • 分层架构设计:
    • 在分层系统种,可以在子系统的每一层使用 Facade Pattern ,减少高层模块对低层模块的依赖。
  • 对遗留系统的封装:
    • 当需要对已有系统添加新的功能或优化时,但不想破坏原有设计,可以通过 Facade Pattern 封装已有系统,提供新的接口。

优点

  1. 降低客户端与子系统的耦合
    1. Client 无需了解 Subsystem 的具体实现。
  1. 提高子系统的灵活性
    1. Subsystem 可以在不影响 Client 的情况下自由修改。
  1. 提高可维护性
    1. Subsystem 的接口变化只需要修改 Facade,而不需要修改 Client 代码

缺点

  1. 外观类可能会成为上帝对象 (了解过多或者负责过多的对象)
  2. 在一定程度上违反开闭原则,子系统添加新功能,可能需要修改外观类。
  • 解决:
    • 使用抽象外观类:将 Facade定义为一个 abstract classinterface,提供基本的功能接口。每次扩展时,可以通过创建新的外观类来实现拓展,替代了直接修改原有的 Facade
// 抽象外观类
public abstract class AbstractSmartHomeFacade {
    public abstract void startMode();
    public abstract void stopMode();
}

// 具体实现类
public class SmartHomeFacade extends AbstractSmartHomeFacade {
    private Light light;
    private SoundSystem soundSystem;
    private AirConditioner airConditioner;

    public SmartHomeFacade() {
        this.light = new Light();
        this.soundSystem = new SoundSystem();
        this.airConditioner = new AirConditioner();
    }

    @Override
    public void startMode() {
        light.turnOn();
        soundSystem.playMusic();
        airConditioner.turnOn();
    }

    @Override
    public void stopMode() {
        light.turnOff();
        soundSystem.stopMusic();
        airConditioner.turnOff();
    }
}

// 新增扩展外观类
public class AdvancedSmartHomeFacade extends SmartHomeFacade {
    private Curtain curtain;

    public AdvancedSmartHomeFacade() {
        super();
        this.curtain = new Curtain();
    }

    @Override
    public void startMode() {
        super.startMode();
        curtain.close();
    }

    @Override
    public void stopMode() {
        super.stopMode();
        curtain.open();
    }
}
    • 使用组合代替继承:通过组合的方式,将新增的功能封装成独立的类,再将其组合进外观类,替代直接 Facade的代码。
public class SmartHomeFacade {
    private List<Object> subsystems = new ArrayList<>();

    public void addSubsystem(Object subsystem) {
        subsystems.add(subsystem);
    }

    public void startAll() {
        for (Object subsystem : subsystems) {
            // 统一调用子系统的 start 方法
            // 可以通过接口或反射实现
        }
    }

    public void stopAll() {
        for (Object subsystem : subsystems) {
            // 统一调用子系统的 stop 方法
        }
    }
}
public class Client {
    public static void main(String[] args) {
        // 创建外观类
        SmartHomeFacade facade = new SmartHomeFacade();

        // 添加子系统
        facade.addSubsystem(new Light());
        facade.addSubsystem(new SoundSystem());
        facade.addSubsystem(new AirConditioner());
        // 省略
        // …………………………………………

        // 启动所有子系统
        System.out.println("Starting all subsystems...");
        facade.startAll();

        // 停止所有子系统
        System.out.println("\nStopping all subsystems...");
        facade.stopAll();
    }
}

案例实现

在源码中的应用——Tomcat

  • 使用 Tomcat 作为 Web 容器时,Coyote 接受浏览器发送的请求,封装为 Request。为了符合 Servlet API 标准,Tomcat 使用 RequestFacade(实现了 HttpServletRequest接口)对内部的 Request对象进行包装。
  • 所以,在 Servlet 中开发者接触到的 Request其实是 RequestFacade,通过 Facade 模式,隐藏了实现细节,确保安全性和封装性。

与其他设计模式的关系

  • 外观模式为现有对象定义了一个新接口, 适配器模式则会试图运用已有的接口。适配器通常只封装一个对象,外观通常会作用于整个对象子系统上。
  • 当只需对客户端代码隐藏子系统创建对象的方式时, 你可以使用抽象工厂模式来代替外观
  • 享元模式展示了如何生成大量的小型对象, 外观则展示了如何用一个对象来代表整个子系统。
  • 外观中介者模式的职责类似: 它们都尝试在大量紧密耦合的类中组织起合作。
    • 为子系统中的所有对象定义了一个简单接口, 但是它不提供任何新功能。 子系统本身不会意识到外观的存在。 子系统中的对象可以直接进行交流。
    • 将系统中组件的沟通行为中心化。 各组件只知道中介者对象, 无法直接相互交流。
  • 外观类通常可以转换为单例模式类, 因为在大部分情况下一个外观对象就足够了。
  • 外观代理模式的相似之处在于它们都缓存了一个复杂实体并自行对其进行初始化。 代理与其服务对象遵循同一接口, 使得自己和服务对象可以互换, 在这一点上它与外观不同。
目录
相关文章
|
2月前
|
设计模式 人工智能 算法
基于多设计模式的状态扭转设计:策略模式与责任链模式的实战应用
接下来,我会结合实战案例,聊聊如何用「策略模式 + 责任链模式」构建灵活可扩展的状态引擎,让抽奖系统的状态管理从「混乱战场」变成「有序流水线」。
设计模式 存储 人工智能
196 0
|
4月前
|
设计模式 C++
【实战指南】设计模式 - 工厂模式
工厂模式是一种面向对象设计模式,通过定义“工厂”来创建具体产品实例。它包含简单工厂、工厂方法和抽象工厂三种形式,分别适用于不同复杂度的场景。简单工厂便于理解但扩展性差;工厂方法符合开闭原则,适合单一类型产品创建;抽象工厂支持多类型产品创建,但不便于新增产品种类。三者各有优缺点,适用于不同设计需求。
175 48
|
5月前
|
设计模式 存储 缓存
Netty源码—9.性能优化和设计模式
本文主要介绍了Netty的两大性能优化工具、FastThreadLocal的源码和总结、Recycler的设计理念/使用/四个核心组件/初始化/对象获取/对象回收/异线程收割对象和总结,以及Netty设计模式的单例模式和策略模式。
206 53
|
6月前
|
设计模式 负载均衡 监控
并发设计模式实战系列(2):领导者/追随者模式
🌟 ​大家好,我是摘星!​ 🌟今天为大家带来的是并发设计模式实战系列,第二章领导者/追随者(Leader/Followers)模式,废话不多说直接开始~
204 0
|
6月前
|
设计模式 监控 Java
并发设计模式实战系列(1):半同步/半异步模式
🌟 ​大家好,我是摘星!​ 🌟今天为大家带来的是并发设计模式实战系列,第一章半同步/半异步(Half-Sync/Half-Async)模式,废话不多说直接开始~
192 0
|
6月前
|
设计模式 运维 监控
并发设计模式实战系列(4):线程池
需要建立持续的性能剖析(Profiling)和调优机制。通过以上十二个维度的系统化扩展,构建了一个从。设置合理队列容量/拒绝策略。动态扩容/优化任务处理速度。检查线程栈定位热点代码。调整最大用户进程数限制。CPU占用率100%
445 0
|
6月前
|
设计模式 消息中间件 监控
并发设计模式实战系列(3):工作队列
🌟 ​大家好,我是摘星!​ 🌟今天为大家带来的是并发设计模式实战系列,第三章,废话不多说直接开始~
185 0
|
6月前
|
设计模式 消息中间件 监控
并发设计模式实战系列(5):生产者/消费者
🌟 ​大家好,我是摘星!​ 🌟今天为大家带来的是并发设计模式实战系列,第五章,废话不多说直接开始~
225 1
|
6月前
|
设计模式 监控 Java
并发设计模式实战系列(6):读写锁
🌟 ​大家好,我是摘星!​ 🌟今天为大家带来的是并发设计模式实战系列,第六章,废话不多说直接开始~
121 0