台北市网站建设_网站建设公司_Spring_seo优化
2026/1/13 8:28:44 网站建设 项目流程

文章目录

  • 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)详解及代码示例

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询