业务逻辑组件可重用的前提是剥离数据访问和外部依赖:依赖抽象接口而非具体实现,配置通过参数传入,行为用函数式参数或枚举+map控制,状态变更显式建模,副作用通过回调暴露,测试覆盖空值、并发与非法状态。

业务逻辑组件必须剥离数据访问和外部依赖
可重用的前提是它不绑定数据库、HTTP客户端或特定配置源。一旦 UserService 里写了 JdbcTemplate 或 RestTemplate,它就只能在 Spring Boot 项目里用,换到 Quarkus 或纯 Java SE 环境就报错。
实操建议:
立即学习“Java免费学习笔记(深入)”;
- 把数据操作抽象成接口,比如
UserRepository,组件只依赖这个接口,不关心它是 JDBC 实现还是 Redis 实现 - 外部调用(如发短信、查征信)统一走策略接口,比如
VerificationService,运行时注入具体实现 - 避免在组件内部读取
application.yml或System.getProperty(),配置项应通过构造函数或方法参数传入
用泛型 + 函数式参数控制行为分支,别写 if-else 堆砌
常见错误是写一个 processOrder() 方法,里面用 if (type.equals("VIP")) { ... } else if (type.equals("GROUP")) { ... } —— 这种代码每加一种类型就得改组件,根本谈不上复用。
实操建议:
立即学习“Java免费学习笔记(深入)”;
- 把差异化逻辑抽成
Function<order result></order>或BiConsumer<order context></order>参数,调用方决定怎么处理 - 对固定分类场景,用枚举 +
Map<ordertype function>></ordertype>预注册,避免每次 new 实例 - 慎用反射或 SPI 自动加载——调试困难、类加载冲突风险高,小团队不如手动注册清晰
状态变更必须显式建模,禁止隐式 side effect
比如一个 applyDiscount() 方法,如果它既修改了 order.total,又悄悄调用了 auditLog.write(),那下游系统就无法预测副作用,也不敢在事务外复用它。
TurboShop是一套使用强大、安全的JAVA语言开发,基于企业级J2EE架构设计的免费商城系统。整个商城逻辑业务搭建在我们自主研发的TurboPortal平台上,保证了商城具备优秀的负载性能、极快的响应速度、稳定的产品质量、牢固的安全特性、流畅的web流程控制、良好的跨平台特性和后续开发的可扩展性。 TurboShop V4.0.0(Spring版) 更新:久别的4.0版本,时隔4年归来。本版
实操建议:
立即学习“Java免费学习笔记(深入)”;
- 组件方法要么返回新对象(如
Order.withDiscountApplied(...)),要么返回明确的状态结果(DiscountResult),绝不直接改入参 - 日志、埋点、通知等非核心逻辑,通过回调接口暴露,比如
onDiscountApplied(Consumer<discountevent>)</discountevent> - 如果真需要事务一致性,把“执行”和“提交”拆开:先
validateAndPlan()返回待执行动作列表,再由上层统一调度
测试边界比功能更重要:重点覆盖空值、并发、非法状态
很多人只测“正常下单成功”,但真实复用场景下,调用方可能传 null 的 userId,或在未初始化的 Context 里调用 calculateFee(),组件崩溃就等于整个业务链路中断。
实操建议:
立即学习“Java免费学习笔记(深入)”;
- 每个 public 方法开头加
Objects.requireNonNull(input, "input must not be null"),不依赖文档提醒调用方 - 用
ThreadLocal或静态缓存的组件,必须提供resetForTest()方法,否则单元测试会互相污染 - 对含时间计算的逻辑(如有效期校验),不要硬写
new Date(),而是接受Clock参数,方便冻结时间做确定性测试
真正难的不是把逻辑写对,而是让别人敢在不知道你所有上下文的情况下,安全地把它粘贴进自己的系统里——这意味着所有假设都要显式声明,所有依赖都要可替换,所有失败都要有明确定义的出口。









