封装是分三层的数据与行为隔离:第一层通过private字段+校验型getter/setter约束访问;第二层以高内聚类和接口抽象划定模块边界;第三层用语义化api、不可变dto等实现系统级抽象,杜绝虚假封装。

封装不是加个 private 就完事,而是有层次、有目的的数据与行为隔离。它解决的核心问题是:外部不该知道的,就别让它知道;外部该用的,就给它清晰、安全、稳定的接口。
封装的第一层:字段与方法级控制
把属性设为 private,提供带校验逻辑的 getter/setter,是最基础但最关键的一步。重点不在“隐藏”,而在“约束”。
- 比如用户手机号字段,
setPhone()内必须做格式校验和空值检查,不合法直接抛异常,不给错误数据入库机会 -
getPhone()可返回脱敏结果(如138****5678),而不是原始值,避免敏感信息意外泄露 - 避免无脑生成所有字段的 getter/setter——只暴露真正需要被外部读写的行为
封装的第二层:类与模块边界设计
一个类不该承担所有职责。把相关数据和操作聚合成高内聚单元,同时明确它“不做什么”,就是模块化封装。
- 订单服务类只管订单状态流转、金额计算,不处理支付调用或物流推送——这些交给 PaymentService 或 LogisticsClient
- 用
package-private(默认访问修饰符)限制同包内协作,防止跨模块随意依赖 - 对外只暴露接口(如
OrderService),实现类(DefaultOrderService)对调用方不可见
封装的第三层:API 与协议抽象
在微服务或组件化场景中,封装延伸到系统边界。你提供的不是一堆方法,而是一组语义明确、契约稳定的 API。
- HTTP 接口返回统一结构(如
{"code":200,"data":{...},"msg":"ok"}),屏蔽内部异常堆栈和数据库字段名 - SDK 包只导出核心类和 Builder 模式构造入口,隐藏工厂、缓存、重试等中间细节
- 使用记录类(
record)定义 DTO,天然不可变,避免外部篡改状态
警惕虚假封装
这些做法看似封装,实则形同虚设:
- 所有字段
private,但配上全套 getter/setter,等于把内部结构完全摊开 - 方法命名模糊(如
doSomething()),不体现意图,迫使调用方去读实现代码 - 把复杂逻辑塞进 setter,导致对象状态变更副作用不可控(比如 setPrice() 自动触发库存预警)










