设计模式-外观模式(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 代理模式

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

房屋鉴定研究院报告系统

一、项目背景与意义 随着城市化进程的加速和房地产市场的蓬勃发展,房屋安全问题日益受到社会各界的广泛关注。房屋鉴定作为确保房屋安全的重要手段,对于保障人民群众生命财产安全、维护社会稳定具有重要意义。然而,传统的房屋鉴定方式存在诸…

webpack-loader的使用

引入css后执行打包命令 "build": "npx webpack --config wk.config.js"发现报错: webpack默认只能处理js其他的像css,图片都需要借助loader来处理 css-loader loader可以用于对模块的源代码进行转换,可以把css看成一个模块&…

并发学习27--多线程 Tomcat 线程池

Tomcat连接器的线程池 socketProcessor也是个线程 Executor处理线程是按照JDK线程池方法处理,优先选用核心线程,再用救急线程,再去阻塞队列,最后采用拒绝策略。 Tomcat线程池与ThreadExecutorPool的区别 Tomcat中的配置 Tomcat …

kafka快速入门+应用

Kafka, 构建TB级异步消息系统 1.快速入门 1.1 阻塞队列 在生产线程 和 消费线程 之间起到了 , 缓冲作用,即避免CPU 资源被浪费掉 BlockingQueue 解决 线程通信 的问题阻塞方法 put 、 take生产者、消费者 模式 生产者:产生数据的线程…

Word中图表题注样式自动编号

需求 在写论文的时候,希望图表题注是下面的样子,其中图号表示为:章的编号-本章中图的序号,而且都是小写数字。 网上找的方法大多是使用 “插入题注” 来插入,此时章的编号是大写的,如“图一-1”。然后再通…

Web前端-HTML

黑马程序员JavaWeb开发教程 一、初识web前端 1、 标准也称为网页标准,由一系列的标准组成,大部分由W3C负责指定 2、 三个部分组成 HTML:负责网页的结构(页面元素和内容)CSS:负责网页的表现(页…

STL--pair 数对

pair 数对&#x1f357; pair是一个模板类,使用时需要引用文件 #include <utility>//通用工具pair可将两个value处理为一个元素。C标准库内多处用到了这个结构。尤其容器 map、unordered_map和unordered_multimap就是使用pair来管理其内部元素(key_value),任何函数如果…

ppt技巧:如何将Word文档大纲中导入到幻灯片中?

在PowerPoint中&#xff0c;将Word文档的大纲导入到新的幻灯片是一种非常实用的技巧。以下是详细的步骤&#xff1a; 首先&#xff0c;需要打开PowerPoint软件并打开原始的幻灯片文件。 在PowerPoint的顶部【开始】菜单栏中&#xff0c;找到并点击“新建幻灯片”按钮&#xff0…

【力扣】142. 环形链表 II

142. 环形链表 II 题目描述 给定一个链表的头节点 head &#xff0c;返回链表开始入环的第一个节点。 如果链表无环&#xff0c;则返回 null。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中的环&am…

微信小程序全屏开屏广告

效果图 代码 <template><view><!-- 自定义头部 --><u-navbar title" " :bgColor"bgColor"><view class"u-nav-slot" slot"left"><view class"leftCon"><view class"countDown…

u盘为什么一插上电脑就蓝屏,u盘一插电脑就蓝屏

u盘之前还好好的&#xff0c;可以传输文件&#xff0c;使用正常&#xff0c;但是最近使用时却出现问题了。只要将u盘一插入电脑&#xff0c;电脑就显示蓝屏。u盘为什么一插上电脑就蓝屏呢?一般&#xff0c;导致的原因有以下几种。一&#xff0c;主板的SATA或IDE控制器驱动损坏…

C语言处理文本模板:格式信函编程

开篇 本篇文章的问题来源为《编程珠玑》第3章其中一个问题&#xff0c;格式信函编程。说白了就是先在文件中定义一个文本模版&#xff0c;然后使用数据库中的数据去填充这个模版&#xff0c;最后得到填充后的文本&#xff0c;并输出。 问题概要 在常去的网店键入你的名字和密码…

Harmony鸿蒙南向驱动开发-SPI接口使用

功能简介 SPI指串行外设接口&#xff08;Serial Peripheral Interface&#xff09;&#xff0c;是一种高速的&#xff0c;全双工&#xff0c;同步的通信总线。SPI是由Motorola公司开发&#xff0c;用于在主设备和从设备之间进行通信。 SPI接口定义了操作SPI设备的通用方法集合…

算法练习第16天|101. 对称二叉树

101. 对称二叉树 力扣链接https://leetcode.cn/problems/symmetric-tree/description/ 题目描述&#xff1a; 给你一个二叉树的根节点 root &#xff0c; 检查它是否轴对称。 示例 1&#xff1a; 输入&#xff1a;root [1,2,2,3,4,4,3] 输出&#xff1a;true示例 2&#x…

品牌百度百科词条创建多少钱?

百度百科作为国内最具权威和影响力的知识型平台&#xff0c;吸引了无数品牌和企业争相入驻。一个品牌的百度百科词条&#xff0c;不仅是对品牌形象的一种提升&#xff0c;更是增加品牌曝光度、提高品牌知名度的重要途径。品牌百度百科词条创建多少钱&#xff0c;这成为了许多企…

玻璃生产线 Web 组态应用案例介绍

玻璃生产线组态可视化 概述 随着工厂信息化、数字化发展&#xff0c;智慧生产车间成为必然发展趋势&#xff0c;通过智能硬件、物联网、大数据等智慧化技术与手段&#xff0c;提高车间生产设备、工艺设备的智能执行能力&#xff0c;从而提升整个车间乃至工厂的智能化、网络化与…

【SpringBoot XSS存储漏洞 拦截器】Java纯后端对于前台输入值的拦截校验实现 一个类加一个注解结束

先看效果&#xff1a; 1.js注入拦截&#xff1a; 2.sql注入拦截 生效只需要两步&#xff1a; 1.创建Filter类&#xff0c;粘贴如下代码&#xff1a; package cn.你的包命.filter; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.IO…

macos 查看 远程服务器是否开放某个端口

想要使用mac查看远程服务器某个端口是否开发&#xff0c;可通过 nc 命令&#xff0c;如下&#xff1a; nc -zv <服务器IP> <端口号>如果该端口开发&#xff0c;结果为&#xff1a;succeeded! Connection to <服务器IP> port <端口号> [类型] succeed…

CLion 2024:为Mac与Win打造的卓越跨平台集成开发环境

CLion 2024作为一款跨平台IDE&#xff0c;CLion 2024不仅完美支持Mac和Windows两大操作系统&#xff0c;更在细节之处展现了其出色的跨平台兼容性。无论你是在Mac的优雅界面下工作&#xff0c;还是在Windows的实用环境中编程&#xff0c;CLion 2024都能为你提供一致且流畅的开发…

Day98:云上攻防-云原生篇K8s安全Config泄漏Etcd存储Dashboard鉴权Proxy暴露

目录 云原生-K8s安全-etcd(Master-数据库)未授权访问 etcdV2版本利用 etcdV3版本利用 云原生-K8s安全-Dashboard(Master-web面板)未授权访问 云原生-K8s安全-Configfile鉴权文件泄漏 云原生-K8s安全-Kubectl Proxy不安全配置 知识点&#xff1a; 1、云原生-K8s安全-etcd未…