低耦合的关键是封装细节、依赖抽象、职责单一和解耦协作。需隐藏内部实现、用接口替代具体类、按需提供访问器、避免链式调用、分离横切关注点,并通过协调者或事件消除双向依赖。

封装不当导致耦合度高,核心问题不是“没加 private”,而是暴露了不该暴露的细节、依赖了具体实现、职责边界模糊。解决的关键是让调用方只关心“做什么”,不感知“怎么做”和“谁来做”。
把内部结构藏好,只留稳定接口
避免直接暴露字段或可变集合,比如不要写 public List
- 属性一律设为 private,连 getter/setter 都要按需提供——不需要修改的字段就不写 setXXX
- 禁止链式调用:如 user.getProfile().getAddress().getCity(),等于把三个类的内部结构全暴露给调用点
- 把路径访问封装成语义化方法:比如 user.getHomeCity(),内部怎么取、跨几个对象,调用方不用知道
用接口代替具体类,切断实现依赖
仅靠 private 封装无法降低类间耦合。真正起作用的是让上层模块依赖抽象(接口或抽象类),而不是某个具体实现。比如 Service 类不应 new AccountDaoImpl,而应接收 IAccountDao 接口实例。
- 定义清晰的小粒度接口(如 OrderRepository、NotificationSender),遵循接口隔离原则
- 通过构造器或 setter 注入接口,而非在类里直接 new 具体类
- 这样 Dao 层换成 MyBatis 实现、Mock 实现或 JPA 实现时,Service 完全不用改
划清职责边界,避免一个类干太多事
高内聚是低耦合的前提。如果 User 类既要存数据、又要校验密码强度、还要发注册邮件、记录操作日志,它必然要和 Validator、EmailService、Logger 等强耦合。
- User 类只管用户核心状态和基本行为(如 isActive()、changePassword())
- 校验逻辑抽成独立的 PasswordValidator,由外部传入或注入
- 日志、通知等横切关注点,用 AOP 或事件机制解耦,不塞进业务类里
用协调者或事件替代双向强引用
当两个类互相持有对方实例(如 OrderService 持有 UserService,UserService 又持有 OrderService),就形成了环形耦合,编译、测试、替换都困难。
- 引入第三方协调类(如 OrderWorkflow),统一调度两者协作
- 改用事件通信:OrderService 发出 OrderCreatedEvent,UserService 订阅并响应,彼此不直接引用
- 或者将共用数据/状态抽离到独立的上下文对象(如 SessionContext),双方都依赖它,但互不依赖对方










