类职责单一、依赖抽象、控制反转、包结构分域是实现高内聚低耦合的核心;应遵循单一职责原则拆分类,用接口隔离变化,构造器注入依赖,按业务域而非技术层分包。

类职责单一:一个类只做一件事
高内聚的核心是让每个类聚焦在明确的职责上,而不是堆砌一堆不相关的功能。比如把用户登录、密码加密、日志记录、数据库连接全塞进一个 UserManager 类里,后续改密码逻辑就得动登录和日志代码,风险高还难测试。
实操建议:
立即学习“Java免费学习笔记(深入)”;
- 用「单一职责原则」倒推:如果类名里带“And”“Or”“Utils”,大概率要拆(如
FileReaderAndWriter→ 拆成FileReader和FileWriter) - 方法超过 10 行、参数超过 4 个、注释里频繁出现“同时…”“另外还要…”,就是内聚松动的信号
- 提取行为时优先封装为小类,而非静态工具类——后者容易演变成上帝对象,破坏封装
依赖抽象而非实现:用接口/抽象类隔离变化
低耦合的关键不是“少写 new”,而是让模块之间靠契约通信。比如订单服务直接依赖 AlipayPayment 类,换微信支付就得改源码;但如果它只依赖 PaymentService 接口,替换实现就只是改 Spring 的 @Bean 注册。
实操建议:
立即学习“Java免费学习笔记(深入)”;
- 对外暴露能力时,优先定义接口(
OrderService),实现类命名为DefaultOrderService或带具体技术标识(JpaOrderService) - 避免在接口中定义与实现强绑定的方法,例如
getJdbcConnection()违反了抽象原则 - Spring 中用
@Qualifier区分多个实现时,别依赖类名字符串,改用自定义注解(@Primary仅适用于默认场景)
控制反转与依赖注入:让容器管对象生命周期
手动 new 对象是耦合的温床,尤其当构造参数层层嵌套时(new OrderService(new PaymentService(new HttpAdapter(...))))。IoC 容器接管后,类只需声明“我需要什么”,不用关心“它从哪来”。
实操建议:
立即学习“Java免费学习笔记(深入)”;
- 构造器注入优于
@Autowired字段注入——前者强制依赖显式化,单元测试也更容易 mock - 避免在 Service 层调用
ApplicationContext.getBean(),这等于绕过 IoC,回归硬编码耦合 - 第三方 SDK(如 RedisTemplate)尽量包装一层接口(
CacheClient),防止某天切换到 Caffeine 时满项目搜redisTemplate.opsForValue()
包结构反映业务边界:避免跨层/跨域引用
包名不是命名空间装饰品。如果 com.example.order 下的类频繁 import com.example.user.UserEntity,且直接操作其字段,说明领域边界模糊——订单逻辑不该知道用户密码怎么加密,更不该直接改用户积分字段。
实操建议:
立即学习“Java免费学习笔记(深入)”;
- 按业务域分包(
order、payment、user),而非技术层(controller、service)——后者容易导致所有模块都依赖dto包,形成隐式耦合 - 跨域交互走防腐层(Anti-Corruption Layer):比如订单要查用户信息,不直接依赖
UserEntity,而是通过UserQueryService接口获取精简 DTO(UserSummary) - Maven 模块划分要和包结构对齐;若
order-service模块能直接引用user-domain的实体类,说明模块拆分没起到隔离作用
真正难的不是写出符合 SOLID 的代码,而是在需求压过来时,忍住不把三个新字段加进已有 VO,不为了“快一点”在 service 里直接 new mapper。内聚和耦合的平衡点,往往藏在第一次重构前的那五分钟犹豫里。










