设计模式-外观模式(Facade)

1. 概念

  • 外观模式(Facade Pattern)是一种结构型设计模式,它提供了一个统一的接口,用于访问子系统中的一群接口。外观模式的主要目的是隐藏系统的复杂性,通过定义一个高层级的接口,使得子系统更容易被使用。在外观模式中,客户端不与每个子系统进行复杂的交互,而是只与提供接口的外观类进行交互

2. 原理结构图

在这里插入图片描述

  • 外观角色(Facade):这是外观模式的核心角色,它提供了一个简化的接口,用于访问子系统中的功能。外观类的作用是封装复杂的子系统操作,让外部客户端无需了解内部细节就能进行交互。
  • 子系统角色(Subsystem):这些是实际执行具体任务的类或模块。它们可能包含多个类和更复杂的逻辑,对于客户端来说,直接与这些子系统交互可能会非常复杂。
  • 客户角色(Client):客户端使用外观类提供的接口与子系统进行交互。通过这种方式,客户端可以简化其代码,因为它只需要与外观类打交道,而不是直接与复杂的子系统打交道。

3. 代码示例

3.1 示例1
  • 有一个复杂的音频播放系统,其中包含多个组件,如CD播放器、MP3播放器、音量控制器等。每个组件都有自己的接口和实现。我们希望提供一个简化的接口,让用户能够轻松地播放音乐,而无需关心底层组件的细节。
// CD播放器接口  
interface CDPlayer {  
    void play();  
    void stop();  
}  
  
// CD播放器实现  
class RealCDPlayer implements CDPlayer {  
    @Override  
    public void play() {  
        System.out.println("Playing CD...");  
    }  
  
    @Override  
    public void stop() {  
        System.out.println("Stopping CD...");  
    }  
}  
  
// MP3播放器接口  
interface MP3Player {  
    void play();  
    void stop();  
}  
  
// MP3播放器实现  
class RealMP3Player implements MP3Player {  
    @Override  
    public void play() {  
        System.out.println("Playing MP3...");  
    }  
  
    @Override  
    public void stop() {  
        System.out.println("Stopping MP3...");  
    }  
}  
  
// 音量控制器接口  
interface VolumeControl {  
    void increaseVolume();  
    void decreaseVolume();  
}  
  
// 音量控制器实现  
class RealVolumeControl implements VolumeControl {  
    @Override  
    public void increaseVolume() {  
        System.out.println("Increasing volume...");  
    }  
  
    @Override  
    public void decreaseVolume() {  
        System.out.println("Decreasing volume...");  
    }  
}

class AudioPlayerFacade {  
    private CDPlayer cdPlayer;  
    private MP3Player mp3Player;  
    private VolumeControl volumeControl;  
  
    public AudioPlayerFacade() {  
        cdPlayer = new RealCDPlayer();  
        mp3Player = new RealMP3Player();  
        volumeControl = new RealVolumeControl();  
    }  
  
    public void playCD() {  
        cdPlayer.play();  
    }  
  
    public void playMP3() {  
        mp3Player.play();  
    }  
  
    public void stop() {  
        cdPlayer.stop();  
        mp3Player.stop();  
    }  
  
    public void increaseVolume() {  
        volumeControl.increaseVolume();  
    }  
  
    public void decreaseVolume() {  
        volumeControl.decreaseVolume();  
    }  
}
public class AudioPlayerClient {  
    public static void main(String[] args) {  
        AudioPlayerFacade audioPlayerFacade = new AudioPlayerFacade();  
  
        audioPlayerFacade.playCD();  
        audioPlayerFacade.increaseVolume();  
        audioPlayerFacade.playMP3();  
        audioPlayerFacade.decreaseVolume();  
        audioPlayerFacade.stop();  
    }  
}
  • 输出
Playing CD...
Increasing volume...
Playing MP3...
Decreasing volume...
Stopping CD...
Stopping MP3...
  • 在这个示例中,AudioPlayerFacade 类充当外观类,它封装了 CDPlayer、MP3Player 和 VolumeControl 组件的实例,并提供了简化的接口供客户端使用。客户端代码只需与外观类进行交互,而无需关心底层组件的实现细节。这使得代码更加简洁和易于维护。

3.2 示例2
  • 智能家居系统是一个很好的例子,用于说明外观模式如何简化复杂系统的使用。在这个场景中,用户可能想要控制多个设备,如灯、电视、空调等,每个设备都有自己的控制接口和实现。通过使用外观模式,我们可以提供一个统一的接口,使得用户能够更容易地控制这些设备。
// 灯的接口  
interface Light {  
    void turnOn();  
    void turnOff();  
}  
  
// 真实的灯实现  
class RealLight implements Light {  
    @Override  
    public void turnOn() {  
        System.out.println("Light is turned on.");  
    }  
  
    @Override  
    public void turnOff() {  
        System.out.println("Light is turned off.");  
    }  
}  
  
// 电视的接口  
interface TV {  
    void turnOn();  
    void turnOff();  
    void changeChannel(int channel);  
}  
  
// 真实的电视实现  
class RealTV implements TV {  
    @Override  
    public void turnOn() {  
        System.out.println("TV is turned on.");  
    }  
  
    @Override  
    public void turnOff() {  
        System.out.println("TV is turned off.");  
    }  
  
    @Override  
    public void changeChannel(int channel) {  
        System.out.println("TV channel changed to: " + channel);  
    }  
}  
  
// 空调的接口  
interface AirConditioner {  
    void turnOn();  
    void turnOff();  
    void setTemperature(int temperature);  
}  
  
// 真实的空调实现  
class RealAirConditioner implements AirConditioner {  
    @Override  
    public void turnOn() {  
        System.out.println("Air conditioner is turned on.");  
    }  
  
    @Override  
    public void turnOff() {  
        System.out.println("Air conditioner is turned off.");  
    }  
  
    @Override  
    public void setTemperature(int temperature) {  
        System.out.println("Air conditioner set to: " + temperature + " degrees.");  
    }  
}

class SmartHomeFacade {  
    private Light light;  
    private TV tv;  
    private AirConditioner airConditioner;  
  
    public SmartHomeFacade() {  
        light = new RealLight();  
        tv = new RealTV();  
        airConditioner = new RealAirConditioner();  
    }  
  
    public void turnOnLight() {  
        light.turnOn();  
    }  
  
    public void turnOffLight() {  
        light.turnOff();  
    }  
  
    public void turnOnTV() {  
        tv.turnOn();  
    }  
  
    public void turnOffTV() {  
        tv.turnOff();  
    }  
  
    public void changeTVChannel(int channel) {  
        tv.changeChannel(channel);  
    }  
  
    public void turnOnAirConditioner() {  
        airConditioner.turnOn();  
    }  
  
    public void turnOffAirConditioner() {  
        airConditioner.turnOff();  
    }  
  
    public void setAirConditionerTemperature(int temperature) {  
        airConditioner.setTemperature(temperature);  
    }  
}

public class SmartHomeClient {  
    public static void main(String[] args) {  
        SmartHomeFacade smartHomeFacade = new SmartHomeFacade();  
  
        // 控制灯  
        smartHomeFacade.turnOnLight();  
        // 做一些其他事情...  
        smartHomeFacade.turnOffLight();  
  
        // 控制电视  
        smartHomeFacade.turnOnTV();  
        smartHomeFacade.changeTVChannel(5);  
        // 做一些其他事情...  
        smartHomeFacade.turnOffTV();  
  
        // 控制空调  
        smartHomeFacade.turnOnAirConditioner();  
        smartHomeFacade.setAirConditionerTemperature(24);  
        // 做一些其他事情...  
        smartHomeFacade.turnOffAirConditioner();  
    }  
}
  • 将看到如下输出:
Light is turned on.
Light is turned off.
TV is turned on.
TV channel changed to: 5
TV is turned off.
Air conditioner is turned on.
Air conditioner set to: 24 degrees.
Air conditioner is turned off.
  • 在这个例子中,SmartHomeFacade 类充当外观类,它封装了 Light、TV 和 AirConditioner 设备的实例,并提供了统一的接口供客户端使用。客户端代码只需与外观类进行交互,而无需关心底层设备的实现细节。这简化了智能家居系统的使用,并使得

4. 优缺点

  • 主要作用
    • 为复杂的子系统提供一个统一、简化的接口,以便更容易地访问子系统中的功能。
  • 优点
    • 简化接口:外观模式为子系统提供了一个简单、统一的接口,使得客户端能够更方便地访问和操作子系统的功能。这有助于减少客户端需要与之交互的接口数量,降低了系统的复杂性。
    • 解耦子系统与客户端:外观模式隐藏了子系统的内部结构和复杂性,客户端只需与外观类进行交互,无需了解子系统的具体实现。这种解耦使得子系统的变化对客户端的影响最小化,提高了系统的可维护性和可扩展性。
    • 提高系统的安全性:通过限制客户端对子系统的直接访问,外观模式有助于防止客户端对子系统进行不当操作或破坏。外观类可以对外部请求进行验证和过滤,确保只有合法的请求能够到达子系统。
    • 灵活性增强:当需要添加新的子系统功能或修改现有功能时,由于客户端只与外观类交互,因此只需修改外观类而无需修改所有客户端代码。这增强了系统的灵活性和可扩展性。
    • 易于管理和控制:外观类可以统一管理和控制对子系统的访问,这有助于维护系统的一致性和完整性。同时,外观类还可以对子系统的操作进行日志记录、性能监控等,方便后续的管理和维护工作。
  • 缺点
    • 违背开闭原则:当需要添加新的子系统或者修改现有子系统时,可能需要更改外观类的实现,这违反了面向对象设计中的开闭原则。
    • 隐藏细节:外观模式隐藏了子系统细节,可能使客户端难以深入了解或定制子系统行为。
    • 增加系统的复杂性:虽然外观模式简化了客户端与系统的交互,但在系统中引入了一个额外的层次,这可能会增加系统的复杂性。
    • 潜在的性能问题:由于所有请求都通过外观类进行转发,这可能会成为性能瓶颈,尤其是在高并发的场景下。

5. 应用场景

5.1 主要包括以下几个方面
  1. 系统复杂度较高:当系统的某一子系统变得过于复杂,不容易使用时,可以使用外观模式来进行简化。外观模式可以将系统的复杂性内部化,对外提供一个简单的接口,使得使用者更加容易使用。
  2. 存在多个复杂接口:当系统中存在多个接口之间的依赖关系比较复杂时,外观模式可以将这些接口进行封装,将复杂性进行内部化,从而简化其使用和维护。
  3. 需要对外封闭:当系统需要对外封闭,外界只能通过一个统一的接口来访问系统时,外观模式非常适用。它可以提供一个统一的接口,用于访问子系统中的一群接口,从而有效提高系统的安全性。
  4. 系统重构:当系统需要进行重构,需要对原有的代码进行优化和改进时,外观模式也能发挥重要作用。它可以将系统功能进行重组,减少耦合,使得代码更加易于理解和维护,从而提高系统的灵活性和可扩展性。
  5. 多层系统构建:在构建多层系统时,外观模式可以作为每层的入口,简化层间调用。例如,在经典的三层架构中,可以在数据访问层和业务逻辑层、业务逻辑层和表示层之间建立外观,降低耦合度。
  6. 维护遗留系统:对于难以维护和扩展的遗留大型系统,如果它包含重要的功能且新的需求开发必须依赖它,使用外观模式可以提供一个简洁的接口,方便新需求的开发。

5.2 实际应用
  1. 操作系统界面:操作系统提供一个统一的界面(外观类),用户通过这个界面可以方便地使用各种功能,而不需要关心底层子系统的具体实现。这个界面简化了用户的操作,隐藏了子系统的复杂性。
  2. 智能家居系统:智能家居系统可以设计一个统一的控制界面(外观类),用户通过这个界面可以控制所有智能设备,而不需要单独操作每个设备的控制接口。这个界面简化了用户的操作,提高了使用的便捷性。
  3. 游戏开发:游戏引擎可以提供一个简单的接口(外观类),游戏开发者通过这个接口可以方便地使用游戏引擎的各种功能,而不需要直接与底层的子系统打交道。这样,游戏开发者可以更加专注于游戏的逻辑和玩法设计,而不用关心底层的实现细节。
  4. 企业级应用:企业级应用可以设计一个统一的业务操作界面(外观类),用户通过这个界面可以完成跨模块的业务操作,而不需要了解每个模块的具体实现和子系统之间的复杂关系。这样,用户的操作变得更加简单和高效。

6. JDK中的使用

  • Java的集合框架:Java集合框架提供了丰富的集合类,如ArrayList、HashSet等,以及各种迭代器接口。为了简化对这些集合类的操作,Java提供了诸如Collections这样的工具类,它作为集合框架的Facade,提供了静态方法对集合进行排序、搜索、线程安全化等操作。这样,客户端代码就不需要直接与各种集合类交互,而是通过Collections这个统一的接口进行操作,降低了系统的复杂性。
  • Java I/O流:Java的I/O流体系非常复杂,涉及字节流、字符流、输入流、输出流等多种类型。为了方便用户使用,Java提供了诸如Files这样的工具类作为Facade,它提供了静态方法用于文件的读写、复制、移动等操作。这样,用户就不需要深入了解I/O流的各种细节,只需要调用Files类提供的方法即可。
  • Java的JDBC API:JDBC API用于Java程序与数据库进行交互。为了简化数据库操作,Java提供了DataSource作为Facade,它封装了数据库连接池的管理和数据库连接的创建过程。用户只需要通过DataSource获取数据库连接,然后执行SQL语句即可,无需关心连接池的具体实现和细节。

7. 注意事项

  • 明确接口简化目标:外观模式的主要目的是简化复杂系统的接口,因此在设计Facade类时,需要明确哪些接口需要被简化,确保Facade类提供的接口既简洁又能够满足客户端的需求。
  • 避免过度封装:虽然外观模式通过封装子系统的复杂性来简化接口,但过度封装可能导致Facade类过于庞大和复杂,反而增加了系统的维护难度。因此,在封装时要适度,避免将过多子系统的细节暴露给Facade类。
  • 保持子系统的独立性:使用外观模式时,应确保子系统之间的独立性。Facade类不应该直接依赖于子系统的具体实现,而应该通过接口或抽象类与子系统交互。这样可以降低Facade类与子系统之间的耦合度,使得子系统更易于维护和扩展。
  • 考虑系统的可扩展性:在设计Facade类时,应预留一定的扩展空间。随着系统的发展,可能需要添加新的功能或修改现有功能。如果Facade类的设计过于僵化,将难以适应这些变化。因此,在设计时应考虑到未来可能的扩展需求。
  • 注意性能问题:虽然外观模式可以简化接口和降低耦合度,但也可能引入性能问题。如果Facade类中的方法涉及大量计算或资源消耗,那么频繁调用这些方法可能导致性能下降。因此,在使用外观模式时,需要关注性能问题,确保Facade类的实现是高效的。

8. 外观模式 VS 代理模式

模式目的模式架构主要角色应用场景
外观模式简化接口,减少系统的复杂性外观角色和子系统角色复杂的系统且包含多个子系统,简化系统的接口
代理模式控制对被代理类的访问代理角色和目标角色访问对象前进行一些预处理操作的场景

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/540535.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

秀米、135、蚂蚁编辑器如何为推文添加附件

秀米、135、蚂蚁编辑器作为第三方的公众号图文排版工具,给从事运营和编辑工作的同学提供了更多的排版选择。不同于公众号自家的编辑器,这些第三方编辑器脱离了微信的直接支持,在很多排版操作上,还是有很多操作不一样的地方。 公众…

UE C++ 学习

UBT(虚幻编译工具(UnrealBuildTool))和UHT虚幻头工具(UnrealHeaderTool) UE有一组用于自动执行编译虚幻引擎过程的工具,包括 UBT和UHT(以及其他工具)。实现这一套工具的目…

R语言 多组堆砌图

目录 数据格式 普通绘图 添加比例 R语言 堆砌图_r语言堆砌图-CSDN博客 关键点在于数据转换步骤和数据比例计算步骤&#xff0c;然后个性化调整图。 ①data <- melt(dat, id.vars c("ID"))##根据分组变为长数据 ②#计算百分比## data2 <- ddply(data, …

Vue 3 中的哪些新特性对提升开发效率最有帮助?

Vue 3 引入了一系列新特性&#xff0c;旨在提升开发效率和改善开发体验。以下是一些对提升开发效率最有帮助的特性&#xff1a; Composition API: Composition API 允许开发者更灵活地组织代码&#xff0c;使得逻辑复用和维护变得更加容易。通过将相关功能的代码组织在一起&…

【Leetcode】2923. 找到冠军 I

文章目录 题目思路代码复杂度分析时间复杂度空间复杂度 结果总结 题目 题目链接&#x1f517; 一场比赛中共有 n n n 支队伍&#xff0c;按从 0 0 0 到 n − 1 n - 1 n−1 编号。 给你一个下标从 0 0 0 开始、大小为 n ∗ n n * n n∗n 的二维布尔矩阵 g r i d grid gr…

【cmake安装】研发环境搭建之cmake安装

背景 因为项目需求&#xff0c;需要家里的Win10 PC安装Ubuntu 20.04虚拟机并搭建编译环境&#xff0c;需要安装cmake编译环境 直接命令安装即可 sudo apt install cmake安装成功后&#xff1a; 3.16版本暂时也够用了

院子里种点什么树风水好呢?

植物本身是一个丰富的生活领域&#xff0c;有着强烈的视觉暗示。其实&#xff0c;在家中养植物&#xff0c;是有许多好处的&#xff0c;它不仅能够装点庭院的环境让家更美丽&#xff0c;还能调节室内的空气质量&#xff0c;对家人的运势也有着非常大的帮助。 不过&#xff0c;并…

向量数据库Chroma学习记录

一 简介 Chroma是一款AI开源向量数据库&#xff0c;用于快速构建基于LLM的应用&#xff0c;支持Python和Javascript语言。具备轻量化、快速安装等特点&#xff0c;可与Langchain、LlamaIndex等知名LLM框架组合使用。 二 基本用法 1 安装 安装方式非常简单&#xff0c;只需…

公司能监控员工电脑屏幕吗

公司能监控员工电脑屏幕吗&#xff1f; 当然可以&#xff01; 公司需要在工作时间去监控员工电脑的。 电脑属于公司财产&#xff0c;公司对于员工在工作期间的上网行为有监控的权利和职责&#xff0c;可以监控员工在工作期间的信息交流&#xff0c;并且对他们的上网行为进行…

为什么负载电流增加时电源电压会下降?

原文来自微信公众号&#xff1a;工程师看海&#xff0c;与我联系&#xff1a;chunhou0820 看海原创视频教程&#xff1a;《运放秘籍》 大家好&#xff0c;我是工程师看海。 在以前的文章中我总是提到当负载电流增加时&#xff0c;电源的输出电压会下降&#xff0c;很多同学在实…

【Java】第十五届蓝桥杯JavaB组第一道填空题

&#xff03;【Java】第十五届蓝桥杯JavaB组第一道填空题 大家好 我是寸铁&#x1f44a; 总结了一篇【Java】第十五届蓝桥杯JavaB组第一道填空题文章 喜欢的小伙伴可以点点关注 &#x1f49d; Java B组 第一道填空题题解如下:

云服务器租用一年、1个月优惠价格表,阿里/腾讯/京东/华为云

现在租一个服务器多少一个月&#xff1f;优惠价格低至3.8元1个月&#xff0c;租用一个月云服务器收费价格表&#xff1a;阿里云和腾讯云2核2G3M服务器优惠价格61元一年&#xff0c;折合一个月5元&#xff0c;京东云轻量云主机5.8元一个月&#xff0c;华为云服务器优惠价格3.8元…

vue中的treeselect下拉框显示不全的解决办法

:appendToBody“true” z-index“9000” 如图&#xff1a;页面中显示的下拉框信息展示不全&#xff0c;就看不见了&#xff0c;也没有滚动条 解决办法&#xff1a;在代码中添加属性【:appendToBody“true” z-index“9000”】 z-index 属性设置元素的堆叠顺序。拥有更高堆叠顺…

安全风险攻击面管理如何提升企业网络弹性?

从研究人员近些年的调查结果来看&#xff0c;威胁攻击者目前非常善于识别和利用最具有成本效益的网络入侵方法&#xff0c;这就凸显出了企业实施资产识别并了解其资产与整个资产相关的安全态势的迫切需要。 目前来看&#xff0c;为了在如此复杂的网络环境中受到最小程度上的网络…

12V降5V5A同步降压芯片WT6023A

12V降5V5A同步降压芯片WT6023A 在今日的产品介绍中&#xff0c;我们将重点讨论一款性能卓越的DC/DC转换器——WT6023A。此款转换器采用抖动频率模式控制架构&#xff0c;以高效、单片同步的方式执行降压操作。其设计能够持续承载达6安培的负载&#xff0c;并且展示出优异的线路…

1.8.5 卷积神经网络近年来在结构设计上的主要发展和变迁——Inception-v4 和 Inception-ResNet

1.8.5 卷积神经网络近年来在结构设计上的主要发展和变迁——Inception-v4 和 Inception-ResNet 前情回顾&#xff1a; 1.8.1 卷积神经网络近年来在结构设计上的主要发展和变迁——AlexNet 1.8.2 卷积神经网络近年来在结构设计上的主要发展和变迁——VGGNet 1.8.3 卷积神经网络近…

configmap里一堆\n怎么解决

1. 问题 在编辑configmap的时候偶尔后遇到configmap里的内容变为一坨&#xff0c;出现一堆\n的情况&#xff0c;如下图&#xff1a; 2. 原因 这个问题是configmap里有一些制表符&#xff08;Tab&#xff09;而不是四个空格(K8S的yaml文件只允许有空格)导致的。 Tips&#xf…

UVC摄像头在虚拟机Ubuntu16.04使用的正确姿势

前言&#xff1a;在Windows使用UVC摄像头是正常的&#xff0c;但在虚拟机Ubuntu中使用可以识别到&#xff0c; 但是一直没有数据出来&#xff0c;一度怀疑是摄像头不行&#xff0c;后来经过仔细研究&#xff0c;才发现是虚拟机usb设置有点问题。一、虚拟机USB设置USB 3.0,不然没…

Modern C++:提升开发效率的语法糖详解与实例

引言 Modern C&#xff0c;特指自C11以来的一系列标准更新&#xff0c;引入了大量旨在增强语言表达力、提高代码清晰度与开发效率的新特性。其中&#xff0c;被称为“语法糖”的便捷语法构造尤为引人注目。这些语法糖不仅简化了程序员的日常编码工作&#xff0c;减少了出错几率…

树的定义、基本术语及性质

在计算机科学中&#xff0c;树&#xff08;Tree&#xff09;是一种非线性的数据结构&#xff0c;用以模拟具有层级关系的数据集合。它由节点&#xff08;Node&#xff09;组成&#xff0c;其中每个节点可以有零个或多个子节点&#xff0c;但只有一个父节点&#xff08;除了根节…