设计模式--外观模式:简化繁琐环境的统一接口

news/2025/11/4 21:02:49/文章来源:https://www.cnblogs.com/yxysuanfa/p/19191408

外观模式:简化复杂系统的统一接口

今天我们来深入探讨外观模式(Facade Pattern),一种结构型设计模式,用于为复杂子系统提供简化的统一接口。外观模式通过封装子系统的复杂逻辑,降低客户端与子系统之间的耦合,使系统更易用。本文将带你实现一个简单的外观模式示例,适合初学者快速上手,同时为有经验的开发者提供进阶建议和优化思路。

外观模式在现实生活中类似遥控器,隐藏复杂操作,提供简单控制。本文使用 Java 语言,通过一个家庭影院系统的场景展示外观模式的实现。让我们开始吧!

前置准备

在开始之前,确保开发环境已就绪:

安装环境

步骤 1: 定义子系统类

家庭影院系统包含多个子系统(如电视、音响、DVD 播放器)。在 com.example.facade.subsystem 中定义:

电视

com.example.facade.subsystem.Television

package com.example.facade.subsystem;
public class Television {
public void turnOn() {
System.out.println("Television is turned on");
}
public void turnOff() {
System.out.println("Television is turned off");
}
public void setInput(String input) {
System.out.println("Television input set to " + input);
}
}

音响

com.example.facade.subsystem.SoundSystem

package com.example.facade.subsystem;
public class SoundSystem {
public void turnOn() {
System.out.println("Sound system is turned on");
}
public void turnOff() {
System.out.println("Sound system is turned off");
}
public void setVolume(int level) {
System.out.println("Sound system volume set to " + level);
}
}

DVD 播放器

com.example.facade.subsystem.DVDPlayer

package com.example.facade.subsystem;
public class DVDPlayer {
public void turnOn() {
System.out.println("DVD player is turned on");
}
public void turnOff() {
System.out.println("DVD player is turned off");
}
public void playMovie(String movie) {
System.out.println("Playing movie: " + movie);
}
}

说明

  • 每个子系统类模拟家庭影院设备的操作。

步骤 2: 创建外观类

创建外观类,提供简化的接口来操作子系统。在 com.example.facade.facade.HomeTheaterFacade 中:

package com.example.facade.facade;
import com.example.facade.subsystem.Television;
import com.example.facade.subsystem.SoundSystem;
import com.example.facade.subsystem.DVDPlayer;
public class HomeTheaterFacade {
private final Television tv;
private final SoundSystem soundSystem;
private final DVDPlayer dvdPlayer;
public HomeTheaterFacade(Television tv, SoundSystem soundSystem, DVDPlayer dvdPlayer) {
this.tv = tv;
this.soundSystem = soundSystem;
this.dvdPlayer = dvdPlayer;
}
public void watchMovie(String movie) {
System.out.println("Setting up home theater to watch a movie...");
tv.turnOn();
tv.setInput("HDMI");
soundSystem.turnOn();
soundSystem.setVolume(10);
dvdPlayer.turnOn();
dvdPlayer.playMovie(movie);
}
public void endMovie() {
System.out.println("Shutting down home theater...");
dvdPlayer.turnOff();
soundSystem.turnOff();
tv.turnOff();
}
}

说明

  • HomeTheaterFacade 封装子系统操作,提供 watchMovieendMovie 两个简单方法。
  • 客户端无需直接与子系统交互。

步骤 3: 客户端代码

com.example.facade.Main 中测试外观模式:

package com.example.facade;
import com.example.facade.facade.HomeTheaterFacade;
import com.example.facade.subsystem.Television;
import com.example.facade.subsystem.SoundSystem;
import com.example.facade.subsystem.DVDPlayer;
public class Main {
public static void main(String[] args) {
// 初始化子系统
Television tv = new Television();
SoundSystem soundSystem = new SoundSystem();
DVDPlayer dvdPlayer = new DVDPlayer();
// 使用外观类
HomeTheaterFacade homeTheater = new HomeTheaterFacade(tv, soundSystem, dvdPlayer);
// 观看电影
homeTheater.watchMovie("Inception");
// 结束播放
homeTheater.endMovie();
}
}

运行输出

Setting up home theater to watch a movie...
Television is turned on
Television input set to HDMI
Sound system is turned on
Sound system volume set to 10
DVD player is turned on
Playing movie: Inception
Shutting down home theater...
DVD player is turned off
Sound system is turned off
Television is turned off

步骤 4: 运行和测试

  1. 编译和运行

    • 在 IDE 中运行 Main 类。
    • 或使用命令行:
      javac src/main/java/com/example/facade/*.java src/main/java/com/example/facade/*/*.java
      java com.example.facade.Main
  2. 测试用例

    • 验证 watchMovie 方法正确调用子系统初始化。
    • 验证 endMovie 方法正确关闭子系统。
    • 测试异常场景(如空电影名)。
  3. 调试技巧

    • 添加日志:使用 System.out 或 SLF4J 记录子系统调用。
    • 检查子系统状态:在调试器中验证每个子系统的调用顺序。
    • 异常处理:在外观类中添加输入验证。

进阶与最佳实践

  • 扩展功能

    • 添加更多操作(如调整画质):
      public void adjustPictureQuality(String mode) {
      tv.setInput(mode);
      System.out.println("Picture quality set to " + mode);
      }
  • 异常处理

    • 添加输入验证:
      public void watchMovie(String movie) {
      if (movie == null || movie.isEmpty()) {
      throw new IllegalArgumentException("Movie name cannot be empty");
      }
      // ...
      }
  • 单例模式结合

    • 将外观类实现为单例:
      public class HomeTheaterFacade {
      private static HomeTheaterFacade instance;
      private final Television tv;
      private final SoundSystem soundSystem;
      private final DVDPlayer dvdPlayer;
      private HomeTheaterFacade() {
      this.tv = new Television();
      this.soundSystem = new SoundSystem();
      this.dvdPlayer = new DVDPlayer();
      }
      public static HomeTheaterFacade getInstance() {
      if (instance == null) {
      instance = new HomeTheaterFacade();
      }
      return instance;
      }
      // ...
      }
  • 测试

    • 使用 JUnit 编写单元测试:
      import org.junit.Test;
      import static org.junit.Assert.*;
      public class HomeTheaterFacadeTest {
      @Test
      public void testWatchMovie() {
      Television tv = new Television();
      SoundSystem soundSystem = new SoundSystem();
      DVDPlayer dvdPlayer = new DVDPlayer();
      HomeTheaterFacade facade = new HomeTheaterFacade(tv, soundSystem, dvdPlayer);
      facade.watchMovie("Test Movie"); // 验证输出
      }
      }
  • 其他应用场景

    • 简化 API 调用:为复杂的 REST API 提供统一接口。
    • 数据库操作:封装多表查询逻辑。
    • 框架集成:Spring 的 JdbcTemplate 类似外观模式。
  • 资源推荐:书籍《设计模式:可复用面向对象软件的基础》、Refactoring Guru 网站。多实践其他设计模式(如代理模式、装饰者模式)。

总结

通过这个外观模式示例,你学会了如何为复杂子系统提供简化的接口,实现了家庭影院系统的统一控制。外观模式在需要降低系统复杂度和解耦客户端与子系统时非常实用,广泛应用于 API 设计和系统集成。

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

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

相关文章

从零实现3D Gaussian Splatting:完整渲染流程的PyTorch代码详解

3D Gaussian Splatting(3DGS)现在几乎成了3D视觉领域的标配技术。NVIDIA把它整合进COSMOS,Meta的新款AR眼镜可以直接在设备端跑3DGS做实时环境捕获和渲染。这技术已经不只是停留在论文阶段了,产品落地速度是相当快…

NOIP2025模拟1

T1:公司的供应链(dag) 思路: 大概就是推出性质但是没写出来。 我们不难发现,对于一个环来说,把环内全部的边删掉是合法的。 然后我们就从一个点开始搜,如果没有环,就把经过的边都标记一下,这是要保留的。然后…

文生视频时代,RustFS如何成为AI资产库的最佳底座?

文生视频时代,RustFS如何成为AI资产库的最佳底座?随着Sora、Pika等文生视频模型引爆2025年AI领域,存储正取代计算成为制约创新的关键瓶颈——处理一段3分钟1080P视频产生的数据量,相当于50万张标准图片的存储需求。…

HTTP 与 SOCKS5 代理协议:企业级选型指南与工程化实践

核心定位与结论 目标读者 企业网络架构、数据平台与安全合规团队 核心结论 协议选型原则:HTTP 代理:优先用于 Web 爬取与 API 调用等应用层流量 SOCKS5 代理:优先用于多协议、TCP/UDP、长连接或非 Web 流量 架构策略…

NOIP2025 游记

11.4 开坑。考完 CSP 像在坐过山车,T3 随时可以挂 40 分,10 号之前睡不好觉。 上午 dmy,打你大坝。 每次考试摸完鱼,只有暴力分,还要给 pyb 编理由真的太难了。 丝之歌拿到了飞针,代价是掉了一千念珠,没关系每关…

用 CodeBuddy CLI + Prompt,从零到可运行:前后端混合管理强大的系统的高效实战

用 CodeBuddy CLI + Prompt,从零到可运行:前后端混合管理强大的系统的高效实战pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-…

最小二乘问题详解8:Levenberg-Marquardt方法

本文系统讲解了Levenberg-Marquardt方法的原理、算法流程与C++实现,阐明其如何通过自适应阻尼在Gauss-Newton与梯度下降之间智能切换,从而高效稳健地求解非线性最小二乘问题。1 引言 对于非线性最小二乘问题的求解来…

20251104周二日记

20251104周二日记补充一下昨晚和师姐聊天收获:不要一篇篇复现,先总体调研。现在的DIFFGS很好,跑着看看。可以当baseline,从其他文章里找创新点和性能突破点。别怕算力限制,可以training free,而且在算力受限情况…

P16.土堆说卷积(可选看)

P16.土堆说卷积(可选看)16.1torch.nn.functional.conv2d的参数(官网)点击查看代码 input:input tensor of shape (minibatch,in_channels,iH,iW) weight:filters of shape (out_channels,in_channelsgroups,kH,k…

25.11.4联考题解

CF1905F 首先判断特殊情况:\(\forall i,p_i=i\) 答案一定是 \(n-2\)。然后考虑一个位置如果已经满足条件我们先统计到答案中,对于不满足条件的位置,考虑去进行交换的贡献。如果存在一个位置满足 \(p_i=i\) 并且前面…

d11.4t4 answer

d11.4t4 answer 题目 题目描述 小 ∗ 有一条地铁线路。 有 \(n\) 个嘟嘟要乘坐地铁。第 \(i\) 个嘟嘟会在第 \(l_i\)站上车,第 \(r_i\) 站下车。为了方便,我们假定有 \(2n\) 个地铁站,且 \(l_i\) , \(r_i\) 互不相…

详细介绍:当AI化身数据炼金术士:初级Python开发者如何将创意炼成黄金代码?—— 老码农的炼金术指南

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

【学习笔记】kafka权威指南——第3章 kafka生产者—向kafka写入资料

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

P15.神经网路的基本骨架——nn.Module的使用

P15.神经网路的基本骨架——nn.Module的使用打开PyTorch官网 1.找到troch.nn的Containers2.打开pycharm:代码-生成-重写方法-选择第一个要初始化的方法__init__3.pycharm运行代码如下点击查看代码 import torch from …

AGC052做题记录

A 其实是简单题,但我是唐诗。 \(2n\) 很简单,前 \(n\) 个和后 \(n\) 个全选 \(0/1\) 即可。可以感觉到正解只需要在这基础上改进,但是胡思乱想了很多没有任何进展。最后意识到最后凑个 \(0\) 即可。 B 做完 T1 ,就…

软工团队第一次作业

作业所属课程 软件工程作业要求 https://edu.cnblogs.com/campus/fzu/202501SoftwareEngineering/homework/13573作业目标 根据真实的需求调研结果,确定具有创新性与实用价值的软件开发项目选题,确保能将智能体合理地…

Windows11-GPT

Windows11-GPT导航 (返回顶部)1. 基于UEFI/GPT的硬盘分区 2. 分区要求2.1 启动分区(ESP) 2.2 微软保留分区(MSR) 2.3 Windows分区(OS) 2.4 恢复工具分区(WinRE) 2.5 数据分区(Other)3. 默认分区布局表 4. 其他实用分区…

1. markdown转word 第一步: markdown转html

1. 简介 最近因为项目需求需要将AI输出的结果导出到word中, 但AI输出的格式为markdown格式,因为word展示内容的时候需要有相应的格式(标题, 段落, 列表, 表格等), 所以不能直接将markdown输出到word中, 否则word中展示…

P14.Dataloader的使用

P14.Dataloader的使用14.1Pytorch官网打开torch.utils.data.DataLoader14.2在pycharm使用DataLoader它返回img和target代码如下:点击查看代码 import torchvision from torch.utils.data import DataLoader #from tor…

docker换源

创建/编辑 /etc/docker/daemon.json {"registry-mirrors": ["https://docker.1ms.run","https://docker-0.unsee.tech","https://docker.m.daocloud.io"],"live-restore…