Java中业务逻辑与数据分离的核心是DO管状态、BO管行为:DO仅承载私有字段和getter,无业务逻辑;BO通过构造注入依赖并操作DO,封装校验与流程;Repository只面向DO,杜绝硬编码耦合。

Java 中业务逻辑和数据的分离,核心是让“状态”归数据对象管,“行为”归业务对象管,而不是把所有东西堆在一个类里。这种分离不是靠删代码实现的,而是靠职责划分、访问控制和协作约定来落地。
用 DO 表达状态,不掺逻辑
Domain Object(DO)只负责承载领域数据和基本状态结构,比如数据库字段映射。它应该:
- 字段全为 private,仅提供必要的 getter(避免 setter,尤其对关键字段如 status、amount)
- 不含业务校验、流程判断、外部调用等行为代码
- 可序列化、可持久化,适合做数据传输或快照记录
- 例如:OrderDO 包含 orderId、totalAmount、createTime,但不包含 cancel() 或 applyDiscount() 方法
用 BO 封装行为,驱动状态变化
Business Object(BO)是真正执行业务规则的载体,它持有 DO 或与 DO 协作,但自身不直接映射数据库:
- 构造时接收 DO(或从 Repository 获取),在其上施加业务操作
- 方法名体现意图,如 confirmPayment()、rollbackIfExpired(),内部封装校验、状态转换、事件触发等
- 可组合策略、调用其他服务,但不暴露底层数据结构细节
- 便于单元测试:传入模拟 DO,断言 BO 的行为结果即可
通过接口和构造注入明确依赖边界
光有 DO 和 BO 还不够,必须切断它们之间的硬编码耦合:
立即学习“Java免费学习笔记(深入)”;
- BO 不应 new OrderDO,而是由上层(如 Service)创建并传入
- 若 BO 需要调用校验、通知、库存服务等,应依赖接口(如 InventoryCheckService),而非具体实现类
- 用构造器注入方式传递依赖,确保 BO 本身无状态、可复用、易替换
- Repository 层只面向 DO 操作,完全不知道 BO 的存在
避免常见反模式
这些写法看似简洁,实则破坏分离原则:
- 在 DO 里写业务方法:比如 OrderDO.cancel() 直接改 status 并发消息——这会让 DO 变成“四不像”,既难测试又难复用
- Service 全权代理所有逻辑:一个方法里查 DO、判条件、改字段、发 MQ、更新 DB——逻辑分散、无法沉淀、难以复用
-
返回可变集合暴露内部结构:如 public List
- getItems(),调用方可能直接修改列表,破坏封装性
- 链式调用穿透多层:user.getProfile().getAddress().getCity() —— 把 DO 的嵌套结构强绑定到业务逻辑中,一改全崩


















