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

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

与其他设计模式的关系

  • 外观模式为现有对象定义了一个新接口, 适配器模式则会试图运用已有的接口。适配器通常只封装一个对象,外观通常会作用于整个对象子系统上。
  • 当只需对客户端代码隐藏子系统创建对象的方式时, 你可以使用抽象工厂模式来代替外观
  • 享元模式展示了如何生成大量的小型对象, 外观则展示了如何用一个对象来代表整个子系统。
  • 外观中介者模式的职责类似: 它们都尝试在大量紧密耦合的类中组织起合作。
    • 为子系统中的所有对象定义了一个简单接口, 但是它不提供任何新功能。 子系统本身不会意识到外观的存在。 子系统中的对象可以直接进行交流。
    • 将系统中组件的沟通行为中心化。 各组件只知道中介者对象, 无法直接相互交流。
  • 外观类通常可以转换为单例模式类, 因为在大部分情况下一个外观对象就足够了。
  • 外观代理模式的相似之处在于它们都缓存了一个复杂实体并自行对其进行初始化。 代理与其服务对象遵循同一接口, 使得自己和服务对象可以互换, 在这一点上它与外观不同。
目录
相关文章
|
4月前
|
设计模式 数据库连接 PHP
PHP中的设计模式:提升代码的可维护性与扩展性在软件开发过程中,设计模式是开发者们经常用到的工具之一。它们提供了经过验证的解决方案,可以帮助我们解决常见的软件设计问题。本文将介绍PHP中常用的设计模式,以及如何利用这些模式来提高代码的可维护性和扩展性。我们将从基础的设计模式入手,逐步深入到更复杂的应用场景。通过实际案例分析,读者可以更好地理解如何在PHP开发中应用这些设计模式,从而写出更加高效、灵活和易于维护的代码。
本文探讨了PHP中常用的设计模式及其在实际项目中的应用。内容涵盖设计模式的基本概念、分类和具体使用场景,重点介绍了单例模式、工厂模式和观察者模式等常见模式。通过具体的代码示例,展示了如何在PHP项目中有效利用设计模式来提升代码的可维护性和扩展性。文章还讨论了设计模式的选择原则和注意事项,帮助开发者在不同情境下做出最佳决策。
|
14天前
|
存储 设计模式 算法
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析
行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算法与对象间职责的分配。行为型模式分为类行为模式和对象行为模式,前者采用继承机制来在类间分派行为,后者采用组合或聚合在对象间分配行为。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象行为模式比类行为模式具有更大的灵活性。 行为型模式分为: • 模板方法模式 • 策略模式 • 命令模式 • 职责链模式 • 状态模式 • 观察者模式 • 中介者模式 • 迭代器模式 • 访问者模式 • 备忘录模式 • 解释器模式
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析
|
14天前
|
设计模式 存储 安全
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
结构型模式描述如何将类或对象按某种布局组成更大的结构。它分为类结构型模式和对象结构型模式,前者采用继承机制来组织接口和类,后者釆用组合或聚合来组合对象。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象结构型模式比类结构型模式具有更大的灵活性。 结构型模式分为以下 7 种: • 代理模式 • 适配器模式 • 装饰者模式 • 桥接模式 • 外观模式 • 组合模式 • 享元模式
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
|
14天前
|
设计模式 存储 安全
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
创建型模式的主要关注点是“怎样创建对象?”,它的主要特点是"将对象的创建与使用分离”。这样可以降低系统的耦合度,使用者不需要关注对象的创建细节。创建型模式分为5种:单例模式、工厂方法模式抽象工厂式、原型模式、建造者模式。
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
|
2月前
|
设计模式 前端开发 JavaScript
JavaScript设计模式及其在实战中的应用,涵盖单例、工厂、观察者、装饰器和策略模式
本文深入探讨了JavaScript设计模式及其在实战中的应用,涵盖单例、工厂、观察者、装饰器和策略模式,结合电商网站案例,展示了设计模式如何提升代码的可维护性、扩展性和可读性,强调了其在前端开发中的重要性。
41 2
|
4月前
|
设计模式 Java 关系型数据库
【Java笔记+踩坑汇总】Java基础+JavaWeb+SSM+SpringBoot+SpringCloud+瑞吉外卖/谷粒商城/学成在线+设计模式+面试题汇总+性能调优/架构设计+源码解析
本文是“Java学习路线”专栏的导航文章,目标是为Java初学者和初中高级工程师提供一套完整的Java学习路线。
505 37
|
4月前
|
设计模式 数据管理 测试技术
PHP中的设计模式:单一职责原则在实战项目中的应用
在软件开发中,设计模式是解决问题的最佳实践。本文通过分析单一职责原则(SRP),探讨了如何运用这一原则来提升PHP项目的可维护性和扩展性。我们将从实际案例出发,展示单一职责原则在业务逻辑分离、代码解耦和提高测试效率方面的应用。无论是新手还是经验丰富的开发者,都能从中获益,进而编写出更健壮、更灵活的PHP代码。
47 5
|
4月前
|
设计模式 安全 PHP
PHP中的设计模式:单一职责原则在实战中的应用
在软件开发中,设计模式是解决常见问题的成熟方案。本文将通过分析单一职责原则这一设计原则,探讨如何在PHP应用程序中应用这一原则来提高代码的可维护性、扩展性和灵活性。我们将从实际案例出发,展示单一职责原则的具体应用方法,并解释其对项目开发周期和质量的积极影响。无论你是PHP初学者还是经验丰富的开发者,都能从中获益,提升你的编程实践水平。
35 4
|
4月前
|
设计模式 Java
Java设计模式-外观模式(11)
Java设计模式-外观模式(11)
|
3月前
|
设计模式 Java
Java设计模式之外观模式
这篇文章详细解释了Java设计模式之外观模式的原理及其应用场景,并通过具体代码示例展示了如何通过外观模式简化子系统的使用。
36 0