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

简介: 外观模式(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 模式,隐藏了实现细节,确保安全性和封装性。

与其他设计模式的关系

  • 外观模式为现有对象定义了一个新接口, 适配器模式则会试图运用已有的接口。适配器通常只封装一个对象,外观通常会作用于整个对象子系统上。
  • 当只需对客户端代码隐藏子系统创建对象的方式时, 你可以使用抽象工厂模式来代替外观
  • 享元模式展示了如何生成大量的小型对象, 外观则展示了如何用一个对象来代表整个子系统。
  • 外观中介者模式的职责类似: 它们都尝试在大量紧密耦合的类中组织起合作。
    • 为子系统中的所有对象定义了一个简单接口, 但是它不提供任何新功能。 子系统本身不会意识到外观的存在。 子系统中的对象可以直接进行交流。
    • 将系统中组件的沟通行为中心化。 各组件只知道中介者对象, 无法直接相互交流。
  • 外观类通常可以转换为单例模式类, 因为在大部分情况下一个外观对象就足够了。
  • 外观代理模式的相似之处在于它们都缓存了一个复杂实体并自行对其进行初始化。 代理与其服务对象遵循同一接口, 使得自己和服务对象可以互换, 在这一点上它与外观不同。
目录
相关文章
|
6天前
|
设计模式 存储 算法
「全网最细 + 实战源码案例」设计模式——命令模式
命令模式(Command Pattern)是一种行为型设计模式,将请求封装成独立对象,从而解耦请求方与接收方。其核心结构包括:Command(命令接口)、ConcreteCommand(具体命令)、Receiver(接收者)和Invoker(调用者)。通过这种方式,命令的执行、撤销、排队等操作更易扩展和灵活。 适用场景: 1. 参数化对象以操作。 2. 操作放入队列或远程执行。 3. 实现回滚功能。 4. 解耦调用者与接收者。 优点: - 遵循单一职责和开闭原则。 - 支持命令组合和延迟执行。 - 可实现撤销、恢复功能。 缺点: - 增加复杂性和类数量。
37 14
「全网最细 + 实战源码案例」设计模式——命令模式
|
6天前
|
设计模式 存储 Java
「全网最细 + 实战源码案例」设计模式——责任链模式
责任链模式(Chain of Responsibility Pattern)是一种行为型设计模式,允许将请求沿着处理者链进行发送。每个处理者可以处理请求或将其传递给下一个处理者,从而实现解耦和灵活性。其结构包括抽象处理者(Handler)、具体处理者(ConcreteHandler)和客户端(Client)。适用于不同方式处理不同种类请求、按顺序执行多个处理者、以及运行时改变处理者及其顺序的场景。典型应用包括日志处理、Java Web过滤器、权限认证等。
43 13
「全网最细 + 实战源码案例」设计模式——责任链模式
|
8天前
|
设计模式 算法 开发者
「全网最细 + 实战源码案例」设计模式——策略模式
策略模式(Strategy Pattern)是一种行为型设计模式,用于定义一系列可替换的算法或行为,并将它们封装成独立的类。通过上下文持有策略对象,在运行时动态切换算法,提高代码的可维护性和扩展性。适用于需要动态切换算法、避免条件语句、经常扩展算法或保持算法独立性的场景。优点包括符合开闭原则、运行时切换算法、解耦上下文与策略实现、减少条件判断;缺点是增加类数量和策略切换成本。示例中通过定义抽象策略接口和具体策略类,结合上下文类实现动态算法选择。
46 8
「全网最细 + 实战源码案例」设计模式——策略模式
|
8天前
|
设计模式 SQL 算法
「全网最细 + 实战源码案例」设计模式——模板方法模式
模板方法模式是一种行为型设计模式,定义了算法的骨架并在父类中实现不变部分,将可变部分延迟到子类实现。通过这种方式,它避免了代码重复,提高了复用性和扩展性。具体步骤由抽象类定义,子类实现特定逻辑。适用于框架设计、工作流和相似算法结构的场景。优点包括代码复用和符合开闭原则,缺点是可能违反里氏替换原则且灵活性较低。
51 7
「全网最细 + 实战源码案例」设计模式——模板方法模式
|
2月前
|
设计模式 前端开发 搜索推荐
前端必须掌握的设计模式——模板模式
模板模式(Template Pattern)是一种行为型设计模式,父类定义固定流程和步骤顺序,子类通过继承并重写特定方法实现具体步骤。适用于具有固定结构或流程的场景,如组装汽车、包装礼物等。举例来说,公司年会节目征集时,蜘蛛侠定义了歌曲的四个步骤:前奏、主歌、副歌、结尾。金刚狼和绿巨人根据此模板设计各自的表演内容。通过抽象类定义通用逻辑,子类实现个性化行为,从而减少重复代码。模板模式还支持钩子方法,允许跳过某些步骤,增加灵活性。
131 11
|
3月前
|
设计模式 安全 Java
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
|
20天前
|
设计模式
「全网最细 + 实战源码案例」设计模式——模式扩展(配置工厂)
该设计通过配置文件和反射机制动态选择具体工厂,减少硬编码依赖,提升系统灵活性和扩展性。配置文件解耦、反射创建对象,新增产品族无需修改客户端代码。示例中,`CoffeeFactory`类加载配置文件并使用反射生成咖啡对象,客户端调用时只需指定名称即可获取对应产品实例。
82 40
|
5月前
|
设计模式 数据库连接 PHP
PHP中的设计模式:提升代码的可维护性与扩展性在软件开发过程中,设计模式是开发者们经常用到的工具之一。它们提供了经过验证的解决方案,可以帮助我们解决常见的软件设计问题。本文将介绍PHP中常用的设计模式,以及如何利用这些模式来提高代码的可维护性和扩展性。我们将从基础的设计模式入手,逐步深入到更复杂的应用场景。通过实际案例分析,读者可以更好地理解如何在PHP开发中应用这些设计模式,从而写出更加高效、灵活和易于维护的代码。
本文探讨了PHP中常用的设计模式及其在实际项目中的应用。内容涵盖设计模式的基本概念、分类和具体使用场景,重点介绍了单例模式、工厂模式和观察者模式等常见模式。通过具体的代码示例,展示了如何在PHP项目中有效利用设计模式来提升代码的可维护性和扩展性。文章还讨论了设计模式的选择原则和注意事项,帮助开发者在不同情境下做出最佳决策。
|
21天前
|
设计模式 关系型数据库
「全网最细 + 实战源码案例」设计模式——简单工厂模式
简单工厂模式是一种创建型设计模式,通过工厂类根据传入参数创建不同类型的对象,也称“静态工厂方法”模式。其结构包括工厂类、产品接口和具体产品类。优点是封装性强、代码复用性好;缺点是扩展性差,增加新产品时需修改工厂类代码,违反开闭原则。适用于对象种类较少且调用者无需关心创建细节的场景。
52 19
|
19天前
|
设计模式 Java
「全网最细 + 实战源码案例」设计模式——生成器模式
生成器模式(Builder Pattern)是一种创建型设计模式,用于分步骤构建复杂对象。它允许用户通过控制对象构造的过程,定制对象的组成部分,而无需直接实例化细节。该模式特别适合构建具有多种配置的复杂对象。其结构包括抽象建造者、具体建造者、指挥者和产品角色。适用于需要创建复杂对象且对象由多个部分组成、构造过程需对外隐藏或分离表示与构造的场景。优点在于更好的控制、代码复用和解耦性;缺点是增加复杂性和不适合简单对象。实现时需定义建造者接口、具体建造者类、指挥者类及产品类。链式调用是常见应用方式之一。
49 12

热门文章

最新文章