设计模式学习(12) 23-10 外观模式

文章目录

  • 0.个人感悟
  • 1. 概念
  • 2. 适配场景
    • 2.1 适合的场景
    • 2.2 常见场景举例
  • 3. 实现方法
    • 3.1 实现思路
    • 3.2 UML类图
    • 3.3 代码示例
  • 4. 优缺点
    • 4.1 优点
    • 4.2 缺点
  • 5. 源码分析(MyBatis Configuration为例)

0.个人感悟

  • 外观模式旨在承上启下,对客户端提供一个统一接口,只定义需要关注的操作,对下统筹各个子系统的操作
  • 外观模式很能体现出解耦的一个手段:分层
  • 外观模式有利于理解迪米特法则(最小知道原则)
  • 外观(门面)可以类比web编程中controller,都是对外提供统一的接口,对内整合自己的业务

1. 概念

英文定义(《设计模式:可复用面向对象软件的基础》)

Provide a unified interface to a set of interfaces in a subsystem. Facade defines a higher-level interface that makes the subsystem easier to use.

中文翻译

为子系统中的一组接口提供一个统一的接口。外观模式定义了一个高层接口,使得子系统更容易使用。

理解

  • 外观模式是一种结构型设计模式,它为复杂的子系统提供一个简单易用的接口
  • 通过引入一个外观类(Facade),将客户端与子系统的复杂交互封装起来
  • 外观模式不改变子系统功能,只是提供了一个更易于访问的入口点
  • 实现了客户端与子系统之间的解耦,使子系统更容易维护和扩展
  • 外观模式符合迪米特法则(最少知识原则),客户端只需要与外观类交互

2. 适配场景

2.1 适合的场景

  1. 需要简化复杂子系统接口时,为子系统提供一个统一的入口
  2. 客户端与多个子系统之间存在大量依赖关系,希望降低耦合度
  3. 需要将子系统分层,为每一层提供统一的接口
  4. 系统需要逐步重构,可以先引入外观模式,然后逐步迁移到新系统

2.2 常见场景举例

  • 电脑启动过程:用户只需按下电源键,无需了解BIOS、CPU、内存等组件的复杂交互
  • 数据库连接:JDBC驱动管理器封装了不同数据库的连接细节
  • Web服务接口:REST API网关整合多个微服务的调用
  • 日志框架:SLF4J作为Logback、Log4j等日志实现的外观
  • 支付系统:支付网关整合支付宝、微信支付、银联等不同支付渠道

3. 实现方法

3.1 实现思路

  1. 识别复杂子系统:分析系统中的各个组件和它们之间的依赖关系
  2. 定义外观接口:确定需要为客户端提供的简化操作
  3. 实现外观类:创建外观类,封装子系统的复杂调用逻辑
  4. 客户端通过外观类访问:客户端只与外观类交互,不直接调用子系统
  5. 可选:抽象外观:如果需要支持多个子系统变体,可以引入抽象外观类

3.2 UML类图

角色说明

  • Facade(外观):为子系统提供一个统一的接口,知道哪些子系统负责处理请求
  • Subsystem Classes(子系统类):实现子系统的功能,处理外观对象指派的任务
  • Client(客户端):通过外观接口与子系统交互,不需要了解子系统的内部细节

3.3 代码示例

背景:电脑的启动重启过程,涉及到很多子系统的操作,但是机箱其实只提供了开机关机重启按钮,这就是很典型的外观模式。简化掉bios等流程,代码如下:
各个子系统,简化为CPU 内存 硬盘:

// CPU子系统publicclassCPU{/** * @description 冻结 * @author bigHao * @date 2026/1/12 **/publicvoidfreeze(){System.out.println("CPU冻结当前任务");}/** * @param position 位置 * @description 跳转 * @author bigHao * @date 2026/1/12 **/publicvoidjump(longposition){System.out.println("CPU跳转到内存位置: "+position);}/** * @description 执行 * @author bigHao * @date 2026/1/12 **/publicvoidexecute(){System.out.println("CPU开始执行指令");}}// 内存子系统publicclassMemory{/** * @param position 位置 * @param data 字节数据 * @description // TODO * @author bigHao * @date 2026/1/12 **/publicvoidload(longposition,byte[]data){System.out.println("内存加载数据到位置: "+position);}/** * @description 释放 * @author bigHao * @date 2026/1/12 **/publicvoidshutdown(){System.out.println("内存释放");}}// 硬盘子系统publicclassHardDrive{/** * @param lba 扇区 * @param size 大小 * @return byte[] * @description 读取数据 * @author bigHao * @date 2026/1/12 **/publicbyte[]read(longlba,intsize){System.out.println("硬盘读取扇区 "+lba+",大小: "+size+" bytes");returnnewbyte[size];}/** * @description 释放 * @author bigHao * @date 2026/1/12 **/publicvoidshutdown(){System.out.println("硬盘读释放");}}

外观类,类似于机箱,这里也可以先定义接口,再提供实现

publicclassComputerFacade{// 启动内存地址常量privatestaticfinallongBOOT_ADDRESS=0x7C00;privatestaticfinallongBOOT_SECTOR=0;privatestaticfinalintSECTOR_SIZE=512;privateCPUcpu;privateMemorymemory;privateHardDrivehardDrive;publicComputerFacade(){cpu=newCPU();memory=newMemory();hardDrive=newHardDrive();}/** * @description 启动 * @author bigHao * @date 2026/1/12 **/publicvoidstart(){System.out.println("=== 开始启动计算机 ===\n");// 硬盘加载数据byte[]bootSector=hardDrive.read(BOOT_SECTOR,SECTOR_SIZE);// 加载到内存memory.load(BOOT_ADDRESS,bootSector);// cpu运行cpu.freeze();cpu.jump(BOOT_ADDRESS);cpu.execute();}/** * @description 关机 * @author bigHao * @date 2026/1/12 **/publicvoidshutdown(){System.out.println("=== 开始关闭计算机 ===\n");// cpu停止cpu.freeze();// 内存停止memory.shutdown();// 硬盘停止hardDrive.shutdown();}/** * @description 重启 * @author bigHao * @date 2026/1/12 **/publicvoidrestart(){System.out.println("=== 开始重启计算机 ===\n");start();shutdown();}}

测试:

publicclassClient{staticvoidmain(){// 只用与门面交互ComputerFacadefacade=newComputerFacade();facade.start();facade.shutdown();facade.restart();}}

输出

=== 开始启动计算机 === 硬盘读取扇区 0,大小: 512 bytes 内存加载数据到位置: 31744 CPU冻结当前任务 CPU跳转到内存位置: 31744 CPU开始执行指令 === 开始关闭计算机 === CPU冻结当前任务 内存释放 硬盘读释放 === 开始重启计算机 === === 开始启动计算机 === 硬盘读取扇区 0,大小: 512 bytes 内存加载数据到位置: 31744 CPU冻结当前任务 CPU跳转到内存位置: 31744 CPU开始执行指令 === 开始关闭计算机 === CPU冻结当前任务 内存释放 硬盘读释放

4. 优缺点

4.1 优点

符合高内聚低耦合原则

  • 降低耦合度:将客户端与复杂的子系统解耦,客户端只依赖外观类
  • 提高内聚性:外观类将相关的子系统操作封装在一起
    提高复用性
  • 外观类可以被多个客户端复用,避免重复编写复杂的子系统调用代码
    增强可维护性
  • 子系统内部变化不会影响客户端,只需要修改外观类
  • 便于分层和模块化管理
    提高可读性
  • 简化了客户端代码,使其更加清晰易懂
  • 提供了清晰的系统边界和接口
    符合开闭原则
  • 可以扩展外观类来添加新功能,而不需要修改现有代码

4.2 缺点

可能违反单一职责原则

  • 如果外观类过于庞大,可能承担了太多职责
    性能开销
  • 额外的调用层可能带来轻微的性能损失
    灵活性受限
  • 对于需要访问子系统特定功能的客户端,可能需要绕过外观类

5. 源码分析(MyBatis Configuration为例)

MyBatis中的Configuration类是外观模式的典型应用,它封装了MyBatis框架的复杂配置和初始化过程。
MyBatis Configuration类结构

// Configuration类充当了MyBatis的外观类publicclassConfiguration{// 存储各种配置信息protectedEnvironmentenvironment;protectedTypeAliasRegistrytypeAliasRegistry;protectedTypeHandlerRegistrytypeHandlerRegistry;protectedMapperRegistrymapperRegistry;protectedMap<String,MappedStatement>mappedStatements;protectedMap<String,Cache>caches;// 各种配置方法 - 对外提供简单接口publicvoidaddMappers(StringpackageName){mapperRegistry.addMappers(packageName);}public<T>voidaddMapper(Class<T>type){mapperRegistry.addMapper(type);}publicvoidaddMappedStatement(MappedStatementms){mappedStatements.put(ms.getId(),ms);}publicMappedStatementgetMappedStatement(Stringid){returnmappedStatements.get(id);}// 类型处理器相关方法publicvoidregisterTypeHandler(TypeHandler<?>typeHandler){typeHandlerRegistry.register(typeHandler);}publicTypeHandler<?>getTypeHandler(Class<?>javaType){returntypeHandlerRegistry.getTypeHandler(javaType);}}

外观模式分析:
外观角色Configuration

  • 封装了MyBatis的所有配置信息
  • 提供了统一的方法来访问各个组件
    子系统角色
  • XMLConfigBuilder:解析XML配置文件
  • MapperRegistry:管理Mapper接口
  • TypeHandlerRegistry:管理类型处理器
  • MappedStatement:管理SQL映射语句
    客户端SqlSessionFactoryBuilderDefaultSqlSessionFactory

设计优势

  1. 简化使用:用户只需要配置Configuration,不需要了解内部复杂的解析和初始化过程
  2. 解耦SqlSessionFactory只依赖Configuration外观类,不直接依赖各个子系统
  3. 可维护性:配置逻辑的变化被封装在Configuration和相关子系统中
  4. 灵活性:可以通过扩展Configuration来支持不同的配置方式
    这种多层外观设计使得MyBatis具有很好的层次结构和模块化,每个层次都封装了特定的复杂性,为上层提供简单的接口。

参考:

  • 韩顺平 Java设计模式
  • 张维鹏 Java设计模式之结构型:外观模式
  • kosamino 设计模式之外观模式(Facade)详解及代码示例

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

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

相关文章

企业AI软件开发观察:极客跳动的Agent设计模式实践与落地

近年来&#xff0c;AI Agent&#xff08;智能体&#xff09;技术正在从理论研究向企业级应用加速落地。企业不再仅关注“AI能做什么”&#xff0c;而更关心“AI如何实际提高业务效率”&#xff0c;尤其是&#xff1a; Agent如何高效推理、处理复杂任务 如何保证决策和执行结果…

AI人脸隐私卫士部署秘籍:快速搭建隐私保护系统

AI人脸隐私卫士部署秘籍&#xff1a;快速搭建隐私保护系统 1. 引言 1.1 业务场景描述 在社交媒体、企业宣传、公共监控等场景中&#xff0c;图像和视频的广泛传播带来了巨大的隐私泄露风险。尤其在多人合照或公共场所拍摄的照片中&#xff0c;未经处理直接发布可能侵犯他人肖…

人体骨骼检测最佳实践:云端GPU+预置镜像,成功率提升90%

人体骨骼检测最佳实践&#xff1a;云端GPU预置镜像&#xff0c;成功率提升90% 引言 在计算机视觉领域&#xff0c;人体骨骼检测&#xff08;又称姿态估计&#xff09;是一项基础而重要的技术。它能够从图像或视频中识别出人体的关键关节位置&#xff08;如肩膀、肘部、膝盖等…

AI人脸隐私卫士绿色框样式修改:前端定制化部署指南

AI人脸隐私卫士绿色框样式修改&#xff1a;前端定制化部署指南 1. 背景与需求分析 随着数字影像的广泛应用&#xff0c;个人隐私保护成为不可忽视的技术议题。尤其在社交分享、公共监控、医疗影像等场景中&#xff0c;人脸信息的泄露风险日益突出。传统的手动打码方式效率低下…

手把手教你处理Vivado注册2035异常(附实操步骤)

破解Vivado“注册2035”困局&#xff1a;从原理到实战的全链路解决方案 你有没有在深夜赶项目时&#xff0c;刚装好Vivado准备开工&#xff0c;结果弹出一个红框&#xff1a;“ License Error 2035 ”&#xff1f; 重启、重装、换账号……试了一圈&#xff0c;问题依旧。网…

MediaPipe Face Detection优化:提升小脸识别率的技巧

MediaPipe Face Detection优化&#xff1a;提升小脸识别率的技巧 1. 背景与挑战&#xff1a;AI时代的人脸隐私保护需求 随着社交媒体和智能设备的普及&#xff0c;图像中的人脸信息泄露风险日益加剧。无论是监控视频、会议截图还是多人合影&#xff0c;未经处理的面部信息可能…

AI人脸隐私卫士处理速度优化:批处理与异步机制实战

AI人脸隐私卫士处理速度优化&#xff1a;批处理与异步机制实战 1. 引言&#xff1a;从单图处理到高并发场景的挑战 随着AI图像处理技术的普及&#xff0c;本地化、低延迟、高安全性的隐私保护工具正成为个人和企业用户的刚需。AI人脸隐私卫士基于Google MediaPipe Face Detec…

HAL_UART_RxCpltCallback错误状态检测与恢复机制

让串口不死&#xff1a;深入HAL_UART_RxCpltCallback的错误检测与自愈设计你有没有遇到过这样的场景&#xff1f;设备在现场跑了三天两夜&#xff0c;突然串口“卡死”了——不再接收任何数据&#xff0c;但也没有报错。重启一下就好了&#xff0c;可谁愿意天天去现场拔电源&am…

UDS协议入门实战:模拟会话控制操作指南

UDS协议实战精讲&#xff1a;从会话控制到安全解锁的完整路径你有没有遇到过这样的场景&#xff1f;在做ECU刷写测试时&#xff0c;明明发送了编程会话请求&#xff08;0x10 02&#xff09;&#xff0c;结果却收到NRC 0x22——“条件不满足”。翻遍手册也没找到到底哪里出了问题…

DeepPoseKit从零开始:云端环境已配好,省去3天折腾时间

DeepPoseKit从零开始&#xff1a;云端环境已配好&#xff0c;省去3天折腾时间 作为一名生物实验室研究员&#xff0c;你是否遇到过这样的困境&#xff1a;想要用AI分析动物行为&#xff0c;却卡在了环境配置这一步&#xff1f;跟着GitHub教程安装Python环境、配置依赖库&#…

MediaPipe姿态估计实战对比:CPU版 vs GPU版推理速度全面评测

MediaPipe姿态估计实战对比&#xff1a;CPU版 vs GPU版推理速度全面评测 1. 背景与选型动机 随着AI在健身指导、动作识别、虚拟试衣和人机交互等场景的广泛应用&#xff0c;人体姿态估计&#xff08;Human Pose Estimation&#xff09;已成为计算机视觉中的核心技术之一。其中…

AI自动打码性能对比:不同模型的效果

AI自动打码性能对比&#xff1a;不同模型的效果 1. 背景与需求分析 随着社交媒体和数字影像的普及&#xff0c;个人隐私保护问题日益突出。在发布合照、街拍或监控截图时&#xff0c;未经处理的人脸信息极易造成隐私泄露。传统手动打码方式效率低下&#xff0c;难以应对多张图…

隐私保护最佳实践:AI人脸卫士部署与调优全攻略

隐私保护最佳实践&#xff1a;AI人脸卫士部署与调优全攻略 1. 引言&#xff1a;为何需要智能人脸隐私保护&#xff1f; 随着社交媒体、云相册和视频会议的普及&#xff0c;个人图像数据正以前所未有的速度被采集和传播。一张看似普通的合照中&#xff0c;可能包含多位未授权出…

智能隐私保护部署指南:AI人脸隐私卫士最佳实践

智能隐私保护部署指南&#xff1a;AI人脸隐私卫士最佳实践 1. 引言 1.1 业务场景描述 在数字化办公、智能安防、内容分享日益普及的今天&#xff0c;图像和视频中的人脸信息已成为敏感数据泄露的主要源头。无论是企业内部会议纪要中的合影、校园活动记录&#xff0c;还是社交…

隐私保护自动化流水线:CI/CD集成实战

隐私保护自动化流水线&#xff1a;CI/CD集成实战 1. 引言&#xff1a;AI 人脸隐私卫士的工程化落地背景 随着企业数字化转型加速&#xff0c;图像数据在内容审核、员工管理、安防监控等场景中被广泛使用。然而&#xff0c;个人隐私泄露风险也随之上升&#xff0c;尤其是在多人…

ModbusTCP报文解析初探:适合新人的系统学习

从零开始读懂ModbusTCP报文&#xff1a;一次彻底的实战解析 你有没有遇到过这样的场景&#xff1f; 调试一个PLC和上位机通信时&#xff0c;数据始终读不出来。Wireshark抓了一堆包&#xff0c;看到满屏的十六进制却无从下手——“这 00 01 00 00 00 06 到底是什么意思&…

如何导入元件库?LTspice Web在线电路仿真扩展教程

如何在 LTspice Web 中导入自定义元件&#xff1f;——从零开始的实战指南 你有没有遇到过这种情况&#xff1a;想用 LTspice Web 快速验证一个新电源 IC 的电路性能&#xff0c;结果打开元件库却发现根本找不到这个芯片&#xff1f;点遍了 F2 的搜索框也没见踪影。 别急。这…

快速理解I2C通信协议:核心要点之数据帧格式

一次搞懂I2C通信&#xff1a;从数据帧到实战避坑全解析 你有没有遇到过这样的场景&#xff1f;明明电路接好了&#xff0c;代码也写得“天衣无缝”&#xff0c;可一读传感器就卡在等待ACK的地方——SDA死死地挂在高电平上&#xff0c;总线像被冻住了一样。这时候&#xff0c;你…

React Native移动电商应用:实战案例(从零实现)

从零打造一个 React Native 电商 App&#xff1a;实战全记录&#xff08;附核心技巧&#xff09; 你有没有过这样的经历&#xff1f; 项目紧急上线&#xff0c;老板说“iOS 和 Android 都要上”&#xff0c;团队却只有两个前端。原生开发人手不够&#xff0c;外包成本太高&am…

Mealy状态机设计实验全过程:从状态图到电路一文说清

从状态图到FPGA&#xff1a;手把手带你实现Mealy序列检测器你有没有遇到过这样的情况——明明写好了Verilog代码&#xff0c;烧进FPGA却发现输出不对&#xff1f;或者仿真时波形跳来跳去&#xff0c;就是抓不到那个关键的“1”&#xff1f;别急&#xff0c;这很可能是因为你在设…