怎么利用 桥接模式 实现业务逻辑与多种底层存储引擎(MySQL、NoSQL)的平滑切换

风浩君_3221

风浩君_3221

2026-05-02

228人浏览

原创

桥接模式中Abstraction(如OrderService)定义业务语义操作,Implementor(如OrderStorage)封装技术实现细节;关键在于按变化原因分离:业务逻辑稳定为抽象层,存储机制多变则归为实现层,通过组合而非继承解耦,运行时依赖注入切换具体实现。

怎么利用 桥接模式 实现业务逻辑与多种底层存储引擎(mysql、nosql)的平滑切换

桥接模式里 Abstraction 和 Implementor 怎么划分才不混淆

关键在识别「谁变、为什么变」。业务逻辑(比如订单创建、库存扣减)是稳定抽象层,它不该知道数据存在 MySQL 还是 Redis;而存储细节(连接管理、SQL 拼接、序列化方式)才是可变实现层。一旦把 OrderService 直接继承 MySQLOrderDao,就锁死了——这不是桥接,是继承耦合。

正确做法是让 OrderService 持有 OrderStorage 接口引用,而 MySQLOrderStorage、RedisOrderStorage 各自实现该接口。这样新增 MongoOrderStorage 时,OrderService 完全不用改。

  • Abstraction(如 OrderService)只定义「我要存订单」「我要查订单ID」这类语义操作
  • Implementor(如 OrderStorage)只定义「怎么写入键值对」「怎么执行 INSERT」这类技术动作
  • 抽象层调用实现层时,传参应保持业务语义(如 Order 对象),而非技术结构(如 Map)

MySQL 和 NoSQL 实现类的差异点必须封装在 ConcreteImplementor 内部

MySQL 需要事务、主键生成、JOIN 查询;Redis 关注 TTL、哈希结构、原子计数器;MongoDB 侧重嵌套文档和索引策略。这些差异不能泄露到 OrderService,否则桥接就失效了。

例如:库存扣减在 MySQL 中用 UPDATE ... SET stock = stock - 1 WHERE id = ? AND stock > 0,在 Redis 中用 DECRBY + EXISTS 判断。这些 SQL 或命令字符串、重试逻辑、失败回滚方式,全部封在各自 ConcreteImplementor 的 decreaseStock() 方法里。

  • MySQL 实现类需处理 SQLException 并转为统一的 StorageException
  • NoSQL 实现类若依赖序列化(如 Jackson),必须在构造时注入,不可硬编码
  • 避免在实现类中做跨存储的兜底逻辑(比如 Redis 失败自动切 MySQL)——这会让抽象层隐式承担路由职责

运行时切换存储引擎的关键是依赖注入而非硬编码 new

如果代码里写死 new MySQLOrderStorage(),再好的桥接结构也白搭。切换引擎必须靠容器或工厂在启动时决定实例类型。

MySQL
MySQL

编写正确的MySQL查询,避免字符集、索引和锁方面的常见陷阱。

下载

Spring 环境下,推荐用 @Profile 或配置项驱动 Bean 注册:

@Bean
@ConditionalOnProperty(name = "storage.type", havingValue = "mysql")
public OrderStorage mysqlStorage() {
    return new MySQLOrderStorage(dataSource);
}
<p>@Bean
@ConditionalOnProperty(name = "storage.type", havingValue = "redis")
public OrderStorage redisStorage(RedisTemplate template) {
return new RedisOrderStorage(template);
}
</p>
  • 绝对不要在业务方法里写 if ("redis".equals(type)) { ... } —— 这等于把桥接退化成 if-else
  • 配置项名(如 storage.type)应统一定义在常量类,避免拼写错误导致加载失败
  • 本地开发时建议默认启用内存实现(如 InMemoryOrderStorage),避免每次启动都连真实 DB

容易被忽略的边界:事务一致性与查询能力落差

桥接能帮你替换存储,但无法抹平底层能力鸿沟。MySQL 支持 ACID 事务,Redis 只能靠 Lua 脚本模拟,MongoDB 的多文档事务有性能代价。这些不是设计模式能解决的,得在 OrderService 的契约里明确约束。

比如「创建订单并扣库存」这个操作,在 MySQL 实现里可放一个事务;在 Redis 实现里就得拆成两步,并接受「订单创建成功但库存扣减失败」的中间态——这个语义差异必须由上层业务兜底,不能指望桥接自动对齐。

  • 所有实现类的 save() 方法,必须文档化其隔离级别与失败场景(如「Redis 实现不保证幂等」)
  • 涉及 JOIN 或复杂聚合的查询,NoSQL 实现类可直接抛 UnsupportedOperationException,而不是强行模拟
  • 测试时必须对每个 ConcreteImplementor 单独跑完整用例,尤其验证异常路径是否一致

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

mysql

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
java
java

Java是一个通用术语,用于表示Java软件及其组件,包括“Java运行时环境 (JRE)”、“Java虚拟机 (JVM)”以及“插件”。php中文网还为大家带了Java相关下载资源、相关课程以及相关文章等内容,供大家免费下载使用。

2023.06.15

11417

6

java正则表达式语法
java正则表达式语法

java正则表达式语法是一种模式匹配工具,它非常有用,可以在处理文本和字符串时快速地查找、替换、验证和提取特定的模式和数据。本专题提供java正则表达式语法的相关文章、下载和专题,供大家免费下载体验。

2023.07.05

8522

9

java自学难吗
java自学难吗

Java自学并不难。Java语言相对于其他一些编程语言而言,有着较为简洁和易读的语法,本专题为大家提供java自学难吗相关的文章,大家可以免费体验。

2023.07.31

7332

8

java配置jdk环境变量
java配置jdk环境变量

Java是一种广泛使用的高级编程语言,用于开发各种类型的应用程序。为了能够在计算机上正确运行和编译Java代码,需要正确配置Java Development Kit(JDK)环境变量。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.08.01

1224

3

java保留两位小数
java保留两位小数

Java是一种广泛应用于编程领域的高级编程语言。在Java中,保留两位小数是指在进行数值计算或输出时,限制小数部分只有两位有效数字,并将多余的位数进行四舍五入或截取。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.08.02

988

3

java基本数据类型
java基本数据类型

java基本数据类型有:1、byte;2、short;3、int;4、long;5、float;6、double;7、char;8、boolean。本专题为大家提供java基本数据类型的相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.02

1456

5

java有什么用
java有什么用

java可以开发应用程序、移动应用、Web应用、企业级应用、嵌入式系统等方面。本专题为大家提供java有什么用的相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.02

3009

5

java在线网站
java在线网站

Java在线网站是指提供Java编程学习、实践和交流平台的网络服务。近年来,随着Java语言在软件开发领域的广泛应用,越来越多的人对Java编程感兴趣,并希望能够通过在线网站来学习和提高自己的Java编程技能。php中文网给大家带来了相关的视频、教程以及文章,欢迎大家前来学习阅读和下载。

2023.08.03

20251

3

配置java环境变量
配置java环境变量

配置Java环境变量是为了让操作系统能够识别和使用Java的相关命令和功能。本专题为大家提供配置java环境变量相关文章,帮助大家解决问题。

2023.08.03

1315

8

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PostgreSQL vs MySQL
PostgreSQL vs MySQL

共1课时 | 192人学习