当前位置: 首页 > news >正文

设计模式-外观模式

外观模式

外观模式 (Facade Pattern) 是一种结构型设计模式,它为子系统中的一组接口提供一个统一的高层接口,使得子系统更容易使用。

核心思想:

想象一下你去看电影。你只需要告诉售票员你想看哪部电影,支付费用,然后拿到票。你不需要关心电影院内部复杂的运作流程,比如排片系统、票务打印系统、座位分配系统、财务系统等等。售票员(或者自助售票机)就扮演了一个“外观”的角色,它简化了你与整个电影院子系统交互的过程。

外观模式就是这样,它隐藏了系统的复杂性,并向客户端提供了一个简化的接口。

模式结构:

外观模式通常包含以下角色:

  1. 外观 (Facade)

    • 知道哪些子系统类负责处理请求。

    • 将客户端的请求委派给适当的子系统对象。

    • 它本身不包含业务逻辑,而是充当子系统的“包装器”或“中介”。

    • 为客户端提供一个单一、简化的入口点。

  2. 子系统类 (Subsystem Classes)

    • 实现子系统的功能。

    • 处理由 Facade 对象委派的任务。

    • 对 Facade 一无所知,即它们不持有 Facade 的引用。

    • 可以有多个子系统类,每个类负责一部分功能。

  3. 客户端 (Client)

    • 通过 Facade 接口与子系统进行交互。

    • 不需要了解子系统的内部结构和复杂性。

示意图:

+----------------+     uses     +---------------------+
|    Client      |------------->|       Facade        |
+----------------+              +---------------------+|| delegates tov+------------------+------------------+|                                     |+-----------------+  +-----------------+  +-----------------+| SubsystemClassA |  | SubsystemClassB |  | SubsystemClassC |+-----------------+  +-----------------+  +-----------------+

优点:

  1. 降低耦合度 (Decoupling)

    • 客户端与子系统解耦:客户端只需要与 Facade 交互,不需要直接依赖于众多的子系统类。当子系统内部发生变化时,只要 Facade 的接口不变,客户端代码就不需要修改。

    • 子系统之间的解耦 (某种程度上):虽然 Facade 本身可能会耦合多个子系统,但它提供了一个单一的入口,有助于管理这些依赖。如果设计得当,子系统之间也可以通过 Facade 间接交互,而不是直接依赖。

  2. 简化接口 (Simplifies Interface):Facade 提供了一个更高层次的、更简单的接口,使得子系统更容易被使用。客户端不需要了解子系统中各个类的复杂关系和调用顺序。

  3. 提高可维护性 (Improved Maintainability):当子系统发生变化时,只需要修改 Facade 或子系统内部,而客户端代码通常不受影响。

  4. 更好的分层 (Better Layering):Facade 可以帮助构建分层系统,Facade 作为服务层,为表现层或业务逻辑层提供统一的访问接口。

  5. 易于理解和使用 (Easier to Understand and Use):对于新的开发者来说,通过 Facade 接口可以更快地了解如何使用一个复杂的子系统。

缺点:

  1. 可能产生“上帝对象” (God Object):如果 Facade 承担了过多的责任,或者包装了太多的子系统功能,它本身可能会变得非常庞大和复杂,违反单一职责原则。

  2. 不符合开闭原则 (Against Open/Closed Principle):当需要为子系统增加新的功能时,可能需要修改 Facade 类的源代码,这违反了开闭原则(对扩展开放,对修改关闭)。当然,可以通过引入其他模式(如装饰器模式或策略模式)来缓解这个问题。

  3. 不能完全隐藏复杂性:Facade 只是提供了一个简化的接口,如果客户端需要更底层的、更灵活的控制,它仍然可以直接访问子系统类(如果子系统类是可见的)。Facade 并不阻止这种直接访问。

适用场景:

  1. 为一个复杂的子系统提供一个简单的接口:当一个系统非常复杂,或者其内部细节难以理解时,可以使用 Facade 来简化客户端的调用。

  2. 需要将客户端与子系统的实现解耦:当希望减少客户端与子系统内部类的依赖关系,以便将来可以独立地修改子系统时。

  3. 构建分层结构:当需要为系统定义清晰的层次,Facade 可以作为某一层(如服务层)的入口。

  4. 包装遗留代码或第三方库:当需要与一个设计不佳或者接口复杂的遗留系统或第三方库集成时,可以使用 Facade 来提供一个更清晰、更符合当前系统设计风格的接口。

代码示例 (Java):

假设我们有一个家庭影院系统,包含 DVD 播放器、投影仪、音响、灯光等子系统。

子系统类:

// 子系统类
class DvdPlayer {public void on() { System.out.println("DVD Player on"); }public void off() { System.out.println("DVD Player off"); }public void play(String movie) { System.out.println("DVD Player playing \"" + movie + "\""); }public void stop() { System.out.println("DVD Player stopped"); }public void eject() { System.out.println("DVD Player eject"); }
}
​
class Projector {public void on() { System.out.println("Projector on"); }public void off() { System.out.println("Projector off"); }public void wideScreenMode() { System.out.println("Projector in widescreen mode (16x9 aspect ratio)"); }
}
​
class Amplifier {public void on() { System.out.println("Amplifier on"); }public void off() { System.out.println("Amplifier off"); }public void setDvd(DvdPlayer dvd) { System.out.println("Amplifier setting DVD player"); }public void setSurroundSound() { System.out.println("Amplifier surround sound on (5.1 channels)"); }public void setVolume(int level) { System.out.println("Amplifier setting volume to " + level); }
}
​
class TheaterLights {public void on() { System.out.println("Theater lights on"); }public void off() { System.out.println("Theater lights off"); }public void dim(int level) { System.out.println("Theater lights dimming to " + level + "%"); }
}
​
// ... 其他子系统如 PopcornPopper, Screen 等

外观类 (Facade):

class HomeTheaterFacade {private DvdPlayer dvd;private Projector projector;private Amplifier amp;private TheaterLights lights;
​public HomeTheaterFacade(DvdPlayer dvd, Projector projector, Amplifier amp, TheaterLights lights) {this.dvd = dvd;this.projector = projector;this.amp = amp;this.lights = lights;}
​public void watchMovie(String movie) {System.out.println("Get ready to watch a movie...");lights.dim(10);projector.on();projector.wideScreenMode();amp.on();amp.setDvd(dvd);amp.setSurroundSound();amp.setVolume(5);dvd.on();dvd.play(movie);}
​public void endMovie() {System.out.println("Shutting movie theater down...");dvd.stop();dvd.eject();dvd.off();amp.off();projector.off();lights.on();}
}

客户端代码:

public class HomeTheaterTestDrive {public static void main(String[] args) {// 初始化子系统DvdPlayer dvd = new DvdPlayer();Projector projector = new Projector();Amplifier amp = new Amplifier();TheaterLights lights = new TheaterLights();
​// 创建外观HomeTheaterFacade homeTheater = new HomeTheaterFacade(dvd, projector, amp, lights);
​// 使用外观的简化接口homeTheater.watchMovie("Raiders of the Lost Ark");System.out.println("\n--- Movie ended, let's turn it off ---\n");homeTheater.endMovie();}
}

在这个例子中,HomeTheaterFacade 封装了启动和关闭家庭影院所需的一系列复杂操作。客户端只需要调用 watchMovie() 和 endMovie() 这样简单的方法,而不需要关心各个设备的具体操作顺序和细节。

与迪米特法则的关系:

外观模式通常有助于遵循迪米特法则。客户端只与 Facade 对象交互(直接朋友),而不需要了解 Facade 内部所依赖的子系统(朋友的朋友)。Facade 自身可能会与多个子系统交互,但从客户端的角度来看,交互点被简化了。

总而言之,外观模式是一个非常有用的模式,当你想要简化复杂系统的使用,或者隔离变化时,它是一个值得考虑的选择。

http://www.xdnf.cn/news/862561.html

相关文章:

  • Java 中 ArrayList、Vector、LinkedList 的核心区别与应用场景
  • 高速ADC数据格式与JESD204B IP数据格式映射关系
  • 数智破局·生态共生:重构全球制造新引擎 2025 WOD制造业数字化博览会即将在沪盛大启幕
  • LINUX64 FTP 1; rsync inotify.sh脚本说明
  • 银行用户评分规则 深度学习
  • 使用 Ansys Q3D 进行电容提取
  • 【android bluetooth 协议分析 14】【HFP详解 1】【案例一: 手机侧显示来电,但车机侧没有显示来电: 讲解AT+CLCC命令】
  • 分析Web3下数据保护的创新模式
  • MVCC理解
  • vscode中无法使用npm node
  • Windows 12确认没了,Win11 重心偏移修Bug
  • 2025年- H65-Lc173--347.前k个高频元素(小根堆,堆顶元素是当前堆元素里面最小的)--Java版
  • HDU-2973 YAPTCHA
  • Maven 构建缓存与离线模式
  • 第二章 进程管理
  • 让音乐“看得见”:使用 HTML + JavaScript 实现酷炫的音频可视化播放器
  • 【论文阅读笔记】Text-to-SQL Empowered by Large Language Models: A Benchmark Evaluation
  • 【RAG优化】rag整体优化建议
  • AI全栈之路:Ubuntu云服务器部署Spring + Vue + MySQL实践指南
  • MySQL索引(index)
  • Mybatis入门到精通
  • Spark实战能力测评模拟题精析【模拟考】
  • 编程技能:格式化打印04,sprintf
  • Ubuntu 16.04 密码找回
  • 区块链安全攻防战:51% 攻击与 Sybil 攻击的应对策略
  • 目标检测任务的评估指标mAP50和mAP50-95
  • OpenCV计算机视觉实战(10)——形态学操作详解
  • 【从前端到后端导入excel文件实现批量导入-笔记模仿芋道源码的《系统管理-用户管理-导入-批量导入》】
  • 目标检测任务的评估指标P-R曲线
  • NPOI操作EXCEL文件 ——CAD C# 二次开发