封装的核心是将状态与操作逻辑绑定于实体内部,通过私有字段、状态校验和公共行为方法(如pay()、cancel())驱动状态变迁,禁止setter,用枚举管理状态,构造函数或工厂方法确保初始合法,只读字段与派生计算收在内部。

封装的核心是把状态和操作状态的逻辑绑定在同一个地方,让外部只通过明确的接口与对象交互,不直接读写字段。业务状态转换逻辑收敛在实体内部,关键在于:用私有字段 + 私有状态校验 + 公共行为方法(而非 getter/setter)来驱动状态变迁。
用行为方法替代 setter
不要暴露状态字段的 setter,而是提供表达业务意图的方法。比如订单从“待支付”变为“已支付”,不应调用 order.setStatus("PAID"),而应定义 pay() 方法:
- 方法内部校验当前状态是否允许支付(如必须是“待支付”)
- 执行状态变更(
this.status = Status.PAID) - 同步更新关联字段(如设置支付时间、生成流水号)
- 可触发领域事件(如发布
OrderPaidEvent)
状态迁移规则内聚在实体中
把“哪些状态能转到哪些状态”这个规则写死在实体里,而不是散落在 service 层。可用枚举+switch、状态机(如 Spring State Machine)、或简单 if 判断:
- 例如
cancel()方法里判断:if (this.status == Status.PAID) { throw new IllegalStateException("已支付订单不可取消"); } - 所有合法迁移路径都在实体方法中显式控制,避免外部绕过规则直接改字段
- 必要时用
enum Status { DRAFT, PAID, SHIPPED, CANCELLED }管理状态值,增强类型安全
构造函数和工厂方法保障初始状态合法性
实体创建时就应处于有效状态,避免出现“半初始化”对象:
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
立即学习“Java免费学习笔记(深入)”;
- 构造函数接收必要参数,直接设置初始状态(如
new Order(userId, items, Status.DRAFT)) - 更推荐静态工厂方法(如
Order.createDraft(userId, items)),隐藏构造细节并做前置校验 - 禁止无参构造 + 多次 setter 赋值的方式,那会破坏封装且易产生无效中间态
敏感字段只读,派生状态延迟计算
对不希望被外部修改的字段(如创建时间、最后更新人),只提供 getter,不提供 setter;对依赖其他字段计算得出的状态(如“是否超时”),用方法实时计算,而非单独字段存储:
-
public Instant getCreatedAt() { return this.createdAt; }—— 只读 -
public boolean isExpired() { return Duration.between(this.createdAt, Instant.now()).toHours() > 24; }—— 派生逻辑收在内部 - 避免
private boolean expired;这种冗余字段,它容易与真实状态不同步
不复杂但容易忽略:封装不是加 private 就完事,而是让每个 public 方法都代表一个完整的、有意义的业务动作,并在其中完成状态检查、变更、副作用处理这一整条链路。

















