设计模式——外观设计模式(结构型)

摘要

本文介绍了外观设计模式,它是一种结构型设计模式,通过引入一个外观类来封装复杂子系统的调用细节,对外提供简单统一的接口。文中通过生活类比、关键角色介绍、使用场景分析以及结构说明等方面对这一模式进行了全面阐述,还涉及了实现方式、适合场景、实战示例和相关思考,有助于读者深入理解外观设计模式的原理和应用。

1. 外观设计模式定义

为复杂子系统提供一个统一的高层接口,使得子系统更易使用。外观模式通过引入一个“外观类(Facade)”,封装内部子系统的调用细节,对外暴露一个简单、统一的接口,隐藏系统的复杂性

1.1. 📦 举个通俗例子(生活类比):

点外卖 = 外观模式:

你使用美团 App 点外卖,只用点菜、下单,不需要关心

  • 餐厅是否接单(子系统 A)
  • 骑手怎么接单(子系统 B)
  • 结算怎么走账(子系统 C)

这就是“外观类”统一封装的行为。

1.2. ✅ 关键角色:

角色

说明

Facade(外观)

高层接口,封装子系统的复杂逻辑,对外提供简洁接口。

SubSystem(子系统)

一组类或模块,完成具体业务逻辑。外观类内部会协调调用它们。

Client(客户端)

只依赖外观类,屏蔽了对内部子系统的直接访问

1.3. ✅ 使用场景:

  • 系统结构复杂,希望对外提供简化接口;
  • 多个系统或模块集成,希望统一接入方式;
  • 用于分层架构(如 Controller -> Service -> Facade -> Subsystem);
  • 旧系统封装重构:用外观封装老接口,屏蔽调用细节。

2. 外观设计模式结构

外观模式包含如下角色:

  • Facade: 外观角色
  • SubSystem:子系统角色

2.1. 外观设计模式类图

2.2. 外观设计模式时序图

3. 外观设计模式实现方式

外观设计模式(Facade Pattern)的实现方式非常清晰明确:通过封装多个子系统的复杂调用逻辑,统一对外提供一个简单接口。

3.1. ✅ 实现步骤(标准实现方式)

3.1.1. 🔹 步骤 1:定义多个子系统(SubSystem)类

@Service
public class RiskScoreService {public int getRiskScore(String userId) {System.out.println("计算用户风险分...");return 75;}
}@Service
public class BlacklistService {public boolean isBlacklisted(String userId) {System.out.println("检查黑名单...");return false;}
}@Service
public class CreditService {public int getCreditLimit(String userId) {System.out.println("获取信用额度...");return 5000;}
}

3.1.2. 🔹 步骤 2:定义外观类(Facade)

@Servcie
public class RiskFacade {@Autowiredprivate final RiskScoreService riskScoreService;@Autowiredprivate final BlacklistService blacklistService;@Autowiredprivate final CreditService creditService;public void assessUserRisk(String userId) {System.out.println("开始用户风控评估...");if (blacklistService.isBlacklisted(userId)) {System.out.println("用户被拉黑,拒绝服务!");return;}int score = riskScoreService.getRiskScore(userId);int credit = creditService.getCreditLimit(userId);System.out.println("风控评估完成,风险分:" + score + ",信用额度:" + credit);}
}

3.1.3. 🔹 步骤 3:客户端只使用 Facade,不关心子系统

public class Client {public static void main(String[] args) {RiskFacade facade = new RiskFacade();facade.assessUserRisk("user123");}
}

3.2. ✅ 在 Spring 项目中的实现方式

如果项目使用 Spring 框架,我们通常会将子系统类标记为 @Service,将外观类作为一个统一入口暴露:

3.2.1. 🔹 子系统类(Spring Bean)

@Service
public class RiskScoreService { ... }@Service
public class BlacklistService { ... }@Service
public class CreditService { ... }

3.2.2. 🔹 外观类作为统一接口

@Servcie
public class RiskFacade {@Autowiredprivate RiskScoreService riskScoreService;@Autowiredprivate BlacklistService blacklistService;@Autowiredprivate CreditService creditService;public void assess(String userId) {// 同上,统一调用子服务}
}

3.2.3. 🔹 Controller 层只依赖外观类

@RestController
@RequestMapping("/risk")
public class RiskController {@Autowiredprivate RiskFacade riskFacade;@GetMapping("/assess")public String assess(@RequestParam String userId) {riskFacade.assess(userId);return "评估完成";}
}

3.3. ✅ 总结:外观模式实现要点

步骤

内容

把多个子系统服务拆分成独立类

建立一个 Facade

类,对外暴露统一方法

客户端只与 Facade

类交互

④(Spring)

把子系统类交给 Spring 管理,外观类通过注入协调调用

4. 外观设计模式适合场景

4.1. ✅ 适合使用外观设计模式的场景

场景

说明

系统结构复杂

系统由多个子系统组成,接口调用复杂,客户端需要简化调用流程。

统一访问入口

需要为多个子系统提供一个统一的接口,客户端只需调用这个接口。

分层架构设计

在分层架构中,用外观层屏蔽底层子系统的实现细节,降低耦合度。

系统重构与迁移

需要将旧系统接口封装,兼容老旧代码,逐步迁移到新系统。

多子系统协调

需要协调多个子系统的调用顺序或组合调用逻辑,外观类负责协调。

4.2. ❌ 不适合使用外观设计模式的场景

场景

原因

系统简单

业务流程简单,接口调用不复杂,使用外观反而增加额外层次和复杂度。

单一功能模块

只涉及一个功能模块,没有必要额外封装统一接口。

频繁变动接口

子系统接口频繁改变,外观层也需频繁修改,维护成本高。

业务高度耦合

业务流程需要客户端灵活控制子系统内部调用,外观隐藏细节不合适。

5. 外观设计模式实战示例

下面是一个金融风控场景下的外观设计模式实战示例,演示如何用Spring管理所有对象,并且使用注解方式注入,避免构造函数注入,方便集成和维护。

5.1. 项目背景

风控系统需要对用户进行风险评估,涉及多个子系统服务:

  • 黑名单查询服务(BlacklistService)
  • 风险分数计算服务(RiskScoreService)
  • 信用额度服务(CreditService)

通过外观模式(RiskFacade)统一暴露给业务调用层,隐藏各子系统复杂调用。

5.2. 子系统服务类

@Service
public class BlacklistService {public boolean isBlacklisted(String userId) {System.out.println("检查用户是否在黑名单中...");// 模拟黑名单检查逻辑return "blacklistedUser".equals(userId);}
}@Service
public class RiskScoreService {public int calculateRiskScore(String userId) {System.out.println("计算用户风险分数...");// 模拟风险分数计算return 80;}
}@Service
public class CreditService {public int getCreditLimit(String userId) {System.out.println("获取用户信用额度...");// 模拟信用额度查询return 10000;}
}

5.3. 外观类

@Component
public class RiskFacade {@Autowiredprivate BlacklistService blacklistService;@Autowiredprivate RiskScoreService riskScoreService;@Autowiredprivate CreditService creditService;public void assessUserRisk(String userId) {System.out.println("=== 开始风控评估 ===");if (blacklistService.isBlacklisted(userId)) {System.out.println("用户 " + userId + " 在黑名单中,拒绝服务!");return;}int riskScore = riskScoreService.calculateRiskScore(userId);int creditLimit = creditService.getCreditLimit(userId);System.out.println("用户 " + userId + " 风险分数: " + riskScore);System.out.println("用户 " + userId + " 信用额度: " + creditLimit);System.out.println("=== 评估结束 ===");}
}

5.4. Controller 层示例

@RestController
@RequestMapping("/risk")
public class RiskController {@Autowiredprivate RiskFacade riskFacade;@GetMapping("/assess")public String assessRisk(@RequestParam String userId) {riskFacade.assessUserRisk(userId);return "风控评估完成";}
}

说明

  • 所有类都由Spring管理,使用 @Service@Component 注解。
  • 外观类 RiskFacade 注入所有子系统服务,作为统一调用入口。
  • 业务层(Controller)只调用外观类接口,避免直接依赖多个子系统。
  • 避免构造函数注入,使用 @Autowired 注解实现自动注入,符合你的要求。

6. 外观设计模式思考

6.1. 门面设计设计模式和DDD中Facade设计区别

6.1.1. 门面设计模式(Facade Pattern)

  • 定义:Facade 是一种结构型设计模式,用于为复杂的子系统提供一个简化的统一接口。它屏蔽了系统的复杂性,客户端通过门面类与子系统交互,而无需直接了解子系统的实现细节。
  • 关注点:简化接口,降低客户端与子系统之间的耦合。
  • 典型用途
    • 为一个复杂系统提供统一的入口。
    • 隐藏子系统的内部复杂逻辑。
    • 提高客户端调用的便利性。

6.1.2. DDD 中的 Facade

  • 定义:在领域驱动设计中,Facade 是一个用于协调多个领域对象领域服务的接口或类。它通常用于应用层,作为应用服务的一部分,负责将客户端的请求转化为对领域层的调用。
  • 关注点:隔离应用层与领域层,简化应用层与外部系统(如 UI、接口调用等)的交互。
  • 典型用途
    • 在应用层对外暴露接口。
    • 封装复杂的领域操作,协调多个领域对象和领域服务。
    • 承载用例(Use Case)的实现逻辑。

6.1.3. 核心区别

维度

门面设计模式(Facade Pattern)

DDD 中的 Facade

目的

为复杂子系统提供一个统一、简化的接口,屏蔽系统内部实现细节。

为外部系统(如 UI 层、API 层)提供对领域层的调用接口。

适用范围

用于封装技术组件(子系统、模块、服务)。

用于封装领域逻辑,暴露领域行为。

位置

通常在技术实现层,用于协调多个技术模块。

通常在应用层,调用领域层服务或聚合根。

关注点

简化客户端调用,隐藏子系统复杂性。

承载用例逻辑,协调领域对象和服务,实现业务需求。

是否直接操作领域

通常不直接操作领域对象,只封装系统内部的模块调用。

直接操作领域对象、聚合根、领域服务等。

6.2. 门面设计模式(Facade Pattern)的设计思想与 Application 层 的职责相似

6.2.1. Application层与门面模式(Facade Pattern)

Application 层(DDD 中的角色)

  • 主要职责
    • 提供用例逻辑(Use Case)服务。
    • 负责协调领域层(Domain Layer)的多个领域对象、领域服务和聚合根。
    • 为外部系统(如 API 层、UI 层等)提供统一的调用接口。
    • 不包含业务逻辑,业务逻辑属于领域层,它仅负责调度领域逻辑
  • 核心思想
    • 简化外部调用(UI 层或 API 层)对复杂领域逻辑的访问。
    • 将应用层与领域层隔离,保证领域层专注于业务规则,而应用层处理系统操作的组合与流程。

门面模式(Facade Pattern)

  • 主要职责
    • 为子系统提供一个统一接口,屏蔽系统内部的复杂性。
    • 将多个子系统或模块的调用逻辑封装在一个类中,外部调用方无需了解子系统的细节。
    • 简化客户端调用,降低外部代码与子系统的耦合度。
  • 核心思想
    • 提供一个简化的、高层次的接口来调用内部复杂的逻辑或子系统。

6.2.2. Application 层和门面模式的相似性

维度

Application 层

门面模式(Facade Pattern)

主要职责

调用领域层的对象和服务,为外部系统提供统一的调用接口。

调用子系统的服务,为客户端提供简化的调用入口。

目标

简化外部系统对复杂领域逻辑的调用,协调领域服务和对象。

隐藏子系统的复杂性,为客户端提供简化的接口。

隐藏复杂性

隐藏领域层内部对象之间的交互细节。

隐藏子系统之间的交互细节。

调用方

外部系统(UI 层、API 层等)。

客户端或其他模块。

实现的粒度

业务用例为单位,封装一个完整的应用逻辑。

技术组件为单位,封装多个模块或服务的调用逻辑。

结论两者都承担了“简化复杂性、统一接口”的职责,但 Application 层更专注于领域逻辑的编排和业务用例,而门面模式更关注技术子系统的整合和封装。

6.3. 项目提供RPC 服务接口设计是不是属于的门面设计模式?

是的,可以认为属于门面设计模式的应用。门面模式(Facade Pattern)定义:为子系统中的一组复杂接口提供一个统一的高层接口,使子系统更易使用。

Spring 中 RPC 服务接口的特点(比如基于 Dubbo、gRPC、Spring Cloud):

特性

说明

📦 对外暴露服务接口

Controller 不再是主角,RPC 接口才是系统“对外的门面”

⚙️ 封装多个底层业务服务(Service、DAO、组件等)

对外提供统一调用入口

🔐 对调用者隐藏实现细节

调用方只知道接口,内部逻辑对其不可见

🔌 提供远程访问能力

一般用于微服务、分布式系统间通信

这与门面模式的核心思想高度一致:对复杂子系统提供统一、简洁、高层次的访问接口。示例场景:

假设你有一个贷款审批系统,下游调用方只需调用如下 RPC 接口:

public interface LoanApprovalRpcService {ApprovalResult approveLoan(LoanApplicationDTO application);
}

而这个接口内部其实会:

  • 校验申请数据
  • 调用风控系统
  • 查询信用评分
  • 写入审批日志
  • 通知第三方平台

这时你暴露的这个 RPC 接口就非常标准地扮演了“门面”角色

  • 对外隐藏了所有复杂的逻辑
  • 调用者只需要关心一个方法:approveLoan(...)

博文参考

  • 4. 外观模式 — Graphic Design Patterns
  • 外观设计模式(门面模式)

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

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

相关文章

LabVIEW磁悬浮轴承传感器故障识别

针对工业高端装备中主动磁悬浮轴承(AMB)的位移传感器故障检测需求,基于 LabVIEW 平台构建了一套高精度故障识别系统。通过集成品牌硬件与 LabVIEW 的信号处理能力,实现了传感器探头故障的实时监测与精准定位,解决了传统…

集成学习三种框架

集成学习通过组合多个弱学习器构建强学习器,常见框架包括Bagging(装袋)、Boosting(提升) 和Stacking(堆叠) 一、Bagging(自助装袋法) 核心思想 从原始数据中通过有放回…

PCI DSS培训记录

22日上午: 整体PCI DSS 结构分享VISA分享全球欺诈风险动态 信用卡被偷枚举攻击依然是最为主要的安全威胁之一(枚举验证码),增加3DS验证防护勒索软件和信息泄漏攻击欺诈分子对AI技术的兴趣日益增加,如换脸软件过验证基于NFC技术利用非接交易进行欺诈成为新的攻击手段,如NF…

数据安全中心是什么?如何做好数据安全管理?

目录 一、数据安全中心是什么 (一)数据安全中心的定义 (二)数据安全中心的功能 1. 数据分类分级 2. 访问控制 3. 数据加密 4. 安全审计 5. 威胁检测与响应 二、数据安全管理的重要性 三、如何借助数据安全中心做好数据安…

黑马Java面试笔记之 微服务篇(业务)

一. 限流 你们项目中有没有做过限流?怎么做的? 为什么要限流呢? 一是并发的确大(突发流量) 二是防止用户恶意刷接口 限流的实现方式: Tomcat:可以设置最大连接数 可以通过maxThreads设置最大Tomcat连接数,实现限流,但是适用于单体架构 Nginx:漏桶算法网关,令牌桶算法自定…

PostgreSQL的扩展 passwordcheck

PostgreSQL的扩展 passwordcheck passwordcheck 是 PostgreSQL 内置的一个密码复杂度检查扩展,用于强制实施基本的密码策略。 一、扩展概述 功能:在创建或修改用户密码时检查密码复杂度目的:防止使用过于简单的密码适用版本:Po…

Go语言学习-->编译器安装

Go语言学习–>编译器安装 Go采用的是UTF-8编码的文本文件存放源代码,理论上使用任何一款文本编辑器都可以做Go语言开发。这里推荐使用VS Code和Goland。 VS Code是微软开源的编辑器,而Goland是jetbrains出品的付费IDE。我们这里使用VS Code …

基于Android的一周穿搭APP的设计与实现 _springboot+vue

开发语言:Java框架:springboot AndroidJDK版本:JDK1.8服务器:tomcat7数据库:mysql 5.7数据库工具:Navicat12开发软件:eclipse/myeclipse/ideaMaven包:Maven3.6 系统展示 APP登录 A…

井字棋——ai PK you

挑战人工智能,体验经典井字棋的对决!AI 拥有强大的逻辑计算能力,每一步都经过精准推演。你能战胜它吗?还是会被 AI 彻底碾压? 特点: 智能 AI,难度可调 极简界面,快速上手 实时胜负…

关于easyx头文件

一、窗口创建 &#xff08;1&#xff09;几种创建方式 #include<easyx.h>//easyx的头文件 #include<iostream> using namespace std;int main() {//创建一个500*500的窗口//参数为&#xff1a;长度&#xff0c;宽度&#xff0c;是否显示黑框&#xff08;无参为不…

【学习记录】Django Channels + WebSocket 异步推流开发常用命令汇总

文章目录 &#x1f4cc; 摘要&#x1f9f0; 虚拟环境管理✅ 创建虚拟环境✅ 删除虚拟环境✅ 激活/切换虚拟环境 &#x1f6e0;️ Django 项目管理✅ 查看 Django 版本✅ 创建 Django 项目✅ 创建 Django App &#x1f4ac; Channels 常用操作✅ 查看 Channels 版本 &#x1f50…

Java线程状态及其流转

在Java编程中&#xff0c;线程是一种重要的并发实体。为了更好地理解和管理多线程应用程序&#xff0c;我们需要清楚线程的不同状态及其流转机制。本文将详细介绍Java中线程的几种主要状态以及它们之间的转换关系。 一、线程状态概述 Java线程的生命周期有多个状态&#xff0…

LabVIEW双光子显微镜开发

基于LabVIEW 开发高性能双光子显微镜系统&#xff0c;聚焦于生物样本深层成像与纳米材料三维表征。实现了超快激光控制、多维数据采集与实时图像重建。系统采用飞秒激光光源与高精度振镜扫描模块&#xff0c;结合 LabVIEW 的 FPGA 实时控制能力&#xff0c;可对活体组织、荧光纳…

数据库操作-MySQL-4(JDBC编程)

JDBC&#xff1a;通过Java代码操作mysql数据库&#xff0c;数据库会提供一些API供我们调用 MySQL、Oracle、等API有差异&#xff0c;但是Java统一了所有接口&#xff0c;即JDBC&#xff1b; 原始api-驱动包&#xff08;类似转接头&#xff09;-统一的api-Java 驱动包&#xff1…

windows修改跃点数调整网络优先级

Windows有两个网卡&#xff0c;一个有线网卡&#xff0c;一个无线网卡&#xff0c;通过修改跃点数来调整优先使用的网卡&#xff0c;这种只是众多设置方式中的其中一种设置方式 文档编写时间&#xff1a;2025年6月 1.打开电脑的网络连接 cmd--ncpa.cpl 在cmd中运行ncpa.cpl可…

实验设计与分析(第6版,Montgomery著,傅珏生译) 第10章拟合回归模型10.9节思考题10.1 R语言解题

本文是实验设计与分析&#xff08;第6版&#xff0c;Montgomery著&#xff0c;傅珏生译) 第10章拟合回归模型10.9节思考题10.1 R语言解题。主要涉及线性回归、回归的显著性、回归系数的置信区间。 vial <- seq(1, 10, 1) Viscosity <- c(160,171,175,182,184,181,188,19…

【深入 LangChain 的 Model I/O】提示设计、模型调用与输出解析全解析

目录 什么是 Model I/O&#xff1f; 一、提示模板&#xff08;PromptTemplate&#xff09; 1.1 什么是提示模板&#xff1f; 1.2 常见提示模板类型 二、模型调用&#xff08;Model Predict&#xff09; 三、输出解析&#xff08;Output Parser&#xff09; 综合示例&…

OD 算法题 B卷【跳格子2】

文章目录 跳格子2 跳格子2 小明和朋友玩跳格子游戏&#xff0c;有n个连续格子组成的圆圈&#xff0c;每个格子有不同的分数&#xff0c;小朋友可以选择从任意格子起跳&#xff0c;但是不能跳连续的格子&#xff0c;不能回头跳&#xff0c;也不能超过一圈&#xff0c;给定一个代…

客户线索商机怎么管?客户线索商机管理工具哪个好?

做销售、搞运营的朋友肯定都有过这种烦恼&#xff1a;每天收到海量客户线索&#xff0c;却不知道从哪条开始跟进&#xff1b;试了好几个管理工具&#xff0c;要么功能太复杂&#xff0c;要么用起来不趁手。其实选对客户线索商机管理工具&#xff0c;就像找到靠谱的 “销售小助手…

008房屋租赁系统技术揭秘:构建智能租赁服务生态

房屋租赁系统技术揭秘&#xff1a;构建智能租赁服务生态 在房地产租赁市场日益活跃的当下&#xff0c;房屋租赁系统成为连接房东与租客的重要数字化桥梁。该系统集成用户管理、房屋信息等多个核心模块&#xff0c;面向管理员、房东和用户三类角色&#xff0c;通过前台展示与后…