封装通过隐藏实现细节、暴露清晰契约实现解耦:定义接口如MailSender,用MailService封装发送逻辑;拆分私有方法使主干逻辑线性;配置绑定实例而非参数;用不可变DTO隔离数据结构依赖。

封装是解耦最基础也最有效的手段——它不靠接口或框架,而是通过隐藏实现细节、暴露清晰契约,让调用方只关心“能做什么”,不操心“怎么做”。
把变化点收进类内部,对外只留稳定方法
业务中常变的不是功能,而是实现方式。比如用户注册时要发欢迎邮件,但邮件服务商可能从 SMTP 换成 SendGrid,再换成企业微信通知。如果 Controller 里直接 new SmtpMailService(),每次换都要改业务代码。
正确做法是定义一个 MailSender 接口,再写一个 MailService 类封装所有发送逻辑:
- MailService 内部管理连接池、重试策略、模板渲染等细节
- 对外只提供 sendWelcome(User user) 这样语义明确的方法
- Controller 或 Service 只调用这一个方法,完全不知道底层走的是 HTTP 还是 TCP
用私有方法拆分流程,主干逻辑保持线性
一个长方法里塞满 if-else 和重复校验,本质是把多个职责混在一起。封装能把它理清楚:
立即学习“Java免费学习笔记(深入)”;
- 把参数校验、状态检查、幂等处理等通用步骤抽成 private 方法
- 主方法变成类似“校验 → 扣减 → 记录 → 通知”的干净链条
- 每个 private 方法只做一件事,且命名体现意图(如 validateInventoryNotZero())
这样改库存规则时,只动扣减部分;加新通知渠道时,只改通知部分——彼此不影响。
把配置和行为绑定在类实例上,而非散落在参数里
常见反模式:同一个方法反复传 timeout、retryTimes、isDryRun 等开关参数,调用点越来越臃肿。
更优方式是构造时注入行为配置:
- new OrderProcessorBuilder().withTimeout(5000).withRetry(3).build()
- 返回的 OrderProcessor 实例已自带策略,调用 process(order) 无需再传一堆控制参数
- 不同场景(测试/灰度/生产)可创建不同配置的实例,复用同一套执行逻辑
用不可变 DTO 封装输入输出,切断数据结构依赖
如果 Service 方法签名是 process(OrderEntity order),就等于把 JPA 实体暴露给了上游——一旦实体加字段、改 getter,所有调用方都得跟着动。
应该封装一层:
- 入参用 OrderCreateRequest(只含必要字段,无 Hibernate 注解)
- 出参用 OrderResult(含 code/msg/data,不含任何持久层痕迹)
- 转换逻辑收在 Service 内部或专用 Converter 类里
这样数据库表结构调整、ORM 框架升级,都不会波及接口契约。


















