高内聚低耦合是可操作的设计习惯:类应专注单一职责,方法服务于同一业务概念;通过接口抽象、委托模式、横切关注点分离(如aop)降低依赖,确保变化影响范围可控、修改集中、替换成本低。

高内聚低耦合不是抽象口号,而是可操作的设计习惯。核心是让类“专注做好一件事”,同时“不和别的类绑太死”。
聚焦单一职责,自然形成高内聚
一个类是否内聚,就看它的所有 public 方法是否服务于同一个业务概念。比如 UserManager 里既有 saveUser()、findUserById(),又混着 sendEmail() 和 generateReport(),那它就明显“干太多事”了——邮件逻辑变(比如加短信通道),报表逻辑变(比如导出格式从 PDF 改 Excel),都得动这个类。
- 每次加新方法前,先问:如果这个功能的实现方式变了(如通知从邮件换成站内信),是否必须改这个类?如果是,说明它不该负责这事
- 把日志、参数校验、JSON 序列化等通用行为抽出来,单独成类或用注解处理,别让业务类自己写
log.info()或new ObjectMapper() - 用 IDE 的 “Find Usages” 查看调用方:如果一个类被 Web 层、定时任务、消息监听器三处调用,但每处只用其中 1–2 个方法,说明它实际承担了多个角色,该拆
用接口和委托代替直接依赖
低耦合的关键不是“不依赖”,而是“依赖得干净”。避免类之间硬编码调用,尤其要防止 A 调 B、B 又调 A 的循环依赖。
- 数据库操作统一交给
UserRepository,定义为接口,实现类叫JpaUserRepository;将来换 Redis 或远程 Feign 调用,只换实现,业务逻辑不动 - 拆分时别急着删方法,先新建
EmailSender类,把原sendEmail()搬过去,再在原类中保留委托方法:emailSender.send(user)—— 调用方完全无感,你却拿到了可测试、可替换的边界 - 避免造一堆模糊的
xxxHelper类;命名要体现能力,比如PasswordEncoder、UserValidator,而不是UserHelper
控制事务、异常、日志等横切关注点的位置
这些不是业务逻辑本身,却常被错误地塞进业务方法里,导致内聚被破坏。
-
@Transactional加在updateProfile()上看似省事,实则把数据一致性、传播行为、重试策略全耦合进了业务签名,这个方法既要做判断又要管资源,职责已超载 - 事务边界应设在更上层(如 Service 方法入口),而非具体业务步骤中;日志、校验、权限检查也应通过 AOP 或拦截器统一处理
- 方法内部少调用本类其他方法,尤其避免长链式调用(
a() → b() → c() → d());每个方法尽量独立完成一个明确子任务
不复杂但容易忽略:高内聚低耦合的本质,是让变化发生时,影响范围可控、修改位置集中、替换成本最低。










