强封装需围绕访问控制、修改路径和影响隔离设计;客户端实体须字段私有化+校验型setter、集合防御性复制、敏感字段禁用通用setter、上下文字段由框架注入且只读。

强封装不是加一堆 private 就完事,而是围绕“谁该访问、怎么访问、改了会不会影响别人”来设计实体变量。在分布式架构中,客户端实体(比如 DTO、Request/Response 类)一旦定义松散,就容易引发接口兼容性断裂、非法数据透传、跨服务校验缺失等问题。优化核心在于:用封装控制数据入口、约束修改路径、隔离内部逻辑。
字段私有化 + 有校验的 setter 是底线
所有业务属性必须声明为 private,禁止 public 或 package-private 字段。setter 方法不能只是简单赋值,要嵌入基础校验逻辑:
- 字符串长度、非空、格式(如邮箱、手机号)在校验阶段拦截
- 数值范围检查(如年龄 0–150、金额 ≥ 0)
- 枚举字段用类型安全方式接收(如用 Status 枚举而非 String status)
- 避免 setter 中抛出运行时异常,推荐统一返回 Result
或抛 IllegalArgumentException,便于上层统一处理
集合类必须防御性复制
客户端实体若含 List、Map、Set 等可变集合,直接暴露 getter 返回原始引用会导致外部篡改内部状态。正确做法是:
- 使用 Collections.unmodifiableList() 包装后返回
- 或在 getter 中 new ArrayList(this.items) 返回副本
- 构造器中对入参集合也做 copy:this.tags = new ArrayList(Objects.requireNonNull(tags))
- 如需频繁修改,考虑用不可变集合库(如 Guava 的 ImmutableList)初始化
敏感字段不暴露 setter,用 builder 或专用方法控制
像 token、password、internalCode 这类字段,不应提供通用 setter。建议:
- 完全移除 setter,仅通过构造器或 Builder 模式一次性注入
- 对外提供 withXXX() 链式方法,内部返回新对象(不可变风格)
- 如必须动态更新,定义明确语义的方法,如 encryptAndSetPassword(String raw),而非 setRawPassword(String)
- 配合 Lombok 的 @Builder(builderMethodName = "hiddenBuilder") 隐藏默认构造入口
与分布式上下文联动的封装增强
在微服务调用链中,实体常需携带 traceId、tenantId、authContext 等上下文信息。这些不该由调用方随意设置,应由框架层注入:
- 定义 protected final 字段(如 protected final String traceId),仅允许内部构造器或框架拦截器写入
- 提供 getTraceId() 但不提供 setTraceId(),防止业务代码误覆盖
- 结合 Spring AOP 或 Filter,在反序列化后自动填充上下文字段(如从 MDC 或 RequestHeader 注入)
- 必要时重写 clone() 或实现深拷贝,确保跨线程/异步调用时不共享上下文引用










