高内聚低耦合的java类需从职责出发,划清边界、显式依赖注入、抽离多变逻辑为接口、剥离通用能力、禁用继承改用组合。

一个高内聚低耦合的 Java 类,不是靠删代码或加接口堆出来的,而是从职责出发、用边界划清楚、靠依赖管住关系。
明确这个类只干一件事
它做的事必须能用一句话说清,比如“把订单状态从 CREATED 更新为 PAID”,而不是“保存订单、发邮件、写日志、调第三方、生成报表”。一旦方法列表里出现 sendEmail() 和 generatePdfReport(),说明它已经响应至少两种变化原因——邮件服务商换和报表格式改,这违反单一职责。新增功能前先问:如果通知方式从邮件换成钉钉,这个类要不要动?答案是“要”,那就该拆。
把多变逻辑抽成接口,自己只持接口不碰实现
比如发通知,别在类里写一堆 if (type == "email") 或 switch (channel)。定义 NotificationSender 接口,只留 void send(NotifyMessage msg);让 EmailSender、SmsSender 各自实现。业务类(如 OrderService)通过构造器注入 NotificationSender,不 import 任何具体实现包,也不 new 任何 sender 实例。测试时直接传 new MockNotificationSender(),零依赖 Spring 容器。
工具行为和通用能力绝不塞进业务类
日期格式化、字符串脱敏、JSON 序列化、密码加密……这些不是订单的职责。抽成独立类,如 DateFormatter、SensitiveMasker、PasswordEncoder,命名体现能力,不叫 OrderHelper 或 UserUtil。业务类需要时,也是通过构造器注入对应接口,而不是 new SimpleDateFormat() 或 new ObjectMapper()。
依赖必须显式注入,且不能越界
数据库操作交给 OrderRepository 接口,HTTP 调用封装成 PaymentClient 接口,配置读取走 AppConfig 接口。所有依赖都通过构造函数传入,类型是接口,不是 JdbcTemplate 或 RestTemplate。Service 层不持有 RedisTemplate,Controller 层不感知 JpaOrderRepository 的存在。这样,换 Redis 为本地缓存、换 MySQL 为 MongoDB,只需提供新实现,业务逻辑一动不动。
避免继承,优先组合
不要为了复用一段 ID 生成逻辑就让 OrderService 继承 IdGeneratorBase。把 IdGenerator 做成接口,用 private final IdGenerator idGenerator 持有,组合进来。子类继承父类,等于绑定了它的字段、方法签名甚至部分实现细节,父类一改,子类可能无声崩溃。而组合灵活、可测、可替换。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











