在Java中如何设计高内聚低耦合的类_Java面向对象设计原则说明

高内聚低耦合指类职责单一且内部协作紧密、类间依赖弱;Java中一眼可判:new具体实现类或import大量非本模块实现类即耦合高,应改用接口+构造器注入,并将行为封装进对应数据类。

什么是高内聚低耦合,Java里怎么一眼看出来

高内聚指一个类职责单一、内部方法紧密协作完成同一目标;低耦合指类之间依赖尽量弱,不直接持有对方实例,不硬编码调用细节。在Java中,最直观的判断方式是看 new 关键字和 import 语句:如果一个类频繁 new 其他具体类、或 import 大量非本模块的实现类(比如 import com.xxx.service.impl.UserServiceImpl),基本就是耦合过高。

用接口隔离 + 依赖注入代替 new 实例

避免在业务类中直接 new UserServiceImpl(),而是声明接口依赖,由外部传入或容器注入:

public class OrderProcessor {
    private final UserService userService; // 依赖接口,不是实现类

    public OrderProcessor(UserService userService) { // 构

造器注入 this.userService = userService; } public void process(Order order) { User user = userService.findById(order.getUserId()); // ... } }
  • 接口 UserService 定义契约,实现类可随时替换(如从 DB 切到缓存)
  • 测试时可传入 MockUserService,无需启动数据库
  • 若用 Spring,用 @Autowired 注入也行,但构造器注入更清晰、不可变、易测
  • 切忌在类内部写 new UserServiceImpl() —— 这会锁死实现,破坏可替换性

把状态和行为封装进同一个类,别拆成“DTO + 工具类”组合

常见反模式:定义 UserDto 存字段,再写个 UserHelper 放所有操作逻辑。这导致数据和行为分离,内聚度归零。

  • 把校验、格式化、状态转换等逻辑放进 User 类本身(只要不违反单一职责)
  • 例如 user.isValidEmail()UserHelper.isValidEmail(user.getEmail()) 更内聚
  • 若逻辑跨多个领域对象(如订单+库存联动),应提取新领域类(OrderFulfillmentService),而不是塞进任一现有类
  • DTO 只用于层间传输(如 Controller → Service),不参与业务逻辑

警惕“上帝类”和过度抽象带来的假低耦合

为解耦而抽象出一堆空接口、模板类、回调函数,结果每个类都依赖 AbstractBaseProcessorCallbackHandlerFactory,实际只是把耦合从具体类转移到抽象结构上。

  • 优先用组合而非继承:PaymentService 持有 NotificationSenderLogRecorder,比继承 BaseTransactionService 更可控
  • 接口粒度要合理:一个 UserService 没问题,但拆成 FindUserPortCreateUserPortUpdateUserPort 就过头了
  • 真正低耦合的表现是:改一个模块(如换支付渠道),只动 AlipayAdapter 和配置,其他类完全不动、不重编译

内聚和耦合不是靠设计模式数量衡量的,而是看修改一处时,有多少其他地方被迫跟着改。每次加新功能前,先问一句:这个逻辑放在这里,是不是只有它自己需要?它是否必须知道别的类怎么实现?