高内聚低耦合是职责清晰后的自然结果,而非设计目标;应聚焦单一职责、用接口隔离依赖、以组合替代继承、将行为封装进数据实体,并通过构造器注入与面向接口编程保障可替换性。

高内聚低耦合不是设计目标,而是职责划分清晰后的自然结果。关键不在“怎么写”,而在“怎么想”——一个类该为谁服务、解决什么问题、变化时影响多大。
聚焦单一职责,用一句话说清类在做什么
如果类名里带“And”“Or”“Helper”“Manager”,或者你无法用一句主谓宾的话描述它的核心作用(比如“校验订单合法性”“生成PDF报表”),那它大概率已经超载。方法是否服务于同一组状态、是否因同一原因而修改,是判断内聚度最实在的标尺。
- OrderService里混着sendEmail()和exportToExcel()?这两个逻辑变化动因完全不同,应拆成EmailNotifier和ReportExporter
- User类里有getFullName()、isValidEmail()、encryptPassword()?前两者属领域行为,后者是安全基础设施,应移入PasswordEncoder
- IDE中右键查看类的“Find Usages”,若被Controller、定时任务、消息监听器各调用不同方法,说明它实际承担多个角色,该分了
依赖必须面向接口,且只通过构造器注入
类内部出现new、static单例、硬编码实现类名,都是耦合的明确信号。低耦合的本质是“我能换掉你,而不改我自己的代码”。
- 把AlipayPayment换成WechatPayment,不应改动OrderProcessor源码,只应替换Spring配置或构造参数
- 禁止import com.xxx.service.impl.XxxServiceImpl;只允许import com.xxx.service.XxxService
- 测试时能直接传new MockUserRepository()进去跑通,就说明依赖设计合格;若需启动数据库或Redis,说明耦合已深入骨髓
把行为装进数据,别让DTO+工具类割裂业务语义
数据和行为分离是内聚杀手。UserDto + UserHelper的组合看似解耦,实则让业务逻辑漂浮无根,难以追踪、无法复用、测试成本翻倍。
- user.isValidEmail()比UserHelper.isValidEmail(user.getEmail())更内聚——验证逻辑属于User本身的状态约束
- 订单状态转换order.transitionTo(PAID)应封装在Order类中,而不是散落在OrderService里一堆if-else
- DTO仅用于跨层传输(如Controller → Service),不参与任何业务判断、格式化或校验
用组合代替继承,靠接口定义协作边界
继承绑定的是实现细节,组合绑定的是能力契约。没有真实“is-a”关系时强行extends,等于给未来埋雷。
- PaymentProcessor不继承AlipayProcessor,而是持有一个PaymentStrategy接口实例,运行时切换策略
- 日志、重试、幂等、脱敏等横切能力,封装成独立组件(RetryPolicy、IdempotentChecker),按需组合进业务类
- 避免抽象基类堆砌模板方法:beforeSave()、afterSave()这类钩子若无默认空实现,子类就被迫重写,反而增加耦合
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











