You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Java清洁架构(Clean Architecture),如何避免直接实例化Repository而应使用UseCase

基于Java清洁架构(Clean Architecture),如何避免直接实例化Repository而应使用UseCase

嘿,针对你在Java清洁架构里遇到的「避免直接实例化Repository,转而用UseCase封装」的问题,我来给你一步步讲清楚怎么实现~

首先得给你点个赞,你现在的项目结构已经踩对了清洁架构的核心规则:把Repository的接口放在domain层,具体实现放在adapter层,这是内层不依赖外层的关键前提。接下来咱们就聚焦怎么用UseCase把Repository的使用完全封装起来,不让上层代码直接碰Repository的实例。


第一步:让UseCase只依赖Repository抽象,封装业务逻辑

清洁架构里,UseCase的职责就是封装核心业务逻辑,它只需要知道“我要调用Repository的哪些方法”,不需要知道这些方法具体是怎么实现的。所以咱们要给StudentUseCase加上构造方法,通过注入的方式拿到Repository接口的实例,而不是自己去new具体实现。

修改后的StudentUseCase代码示例:

// usecase/StudentUseCase.java
package usecase;

import domain.entity.Student;
import domain.repository.StudentRepo;

public class StudentUseCase {
    // 只依赖domain层的抽象接口,完全不碰adapter里的具体实现
    private final StudentRepo studentRepo;

    // 用构造方法注入Repository,保证UseCase创建时就有可用的实例
    public StudentUseCase(StudentRepo studentRepo) {
        this.studentRepo = studentRepo;
    }

    // 在这里封装所有和学生相关的业务操作
    public void createStudent(Student student) {
        // 先做业务校验:比如学生ID不能为空
        if (student.getId() == null || student.getId().trim().isEmpty()) {
            throw new IllegalArgumentException("学生ID不能为空");
        }
        // 再调用Repository的方法做数据操作
        studentRepo.save(student);
    }

    // 比如根据ID查询学生的业务方法
    public Student getStudentById(String studentId) {
        Student student = studentRepo.findById(studentId);
        // 也可以在这里加业务逻辑,比如判断学生是否存在
        if (student == null) {
            throw new RuntimeException("未找到ID为" + studentId + "的学生");
        }
        return student;
    }
}

第二步:在最外层处理Repository实例化和依赖注入

清洁架构的依赖规则是外层可以依赖内层,所以只有最外层的代码(比如你的Main类,或者Spring里的配置类)才有资格去实例化Repository的具体实现,然后把它传给UseCase。这样上层业务代码就完全不用知道StudentRepoImpl的存在,只需要和UseCase打交道。

修改后的Main类代码示例:

// Main.java
import adapter.StudentRepoImpl;
import domain.entity.Student;
import usecase.StudentUseCase;

public class Main {
    public static void main(String[] args) {
        // 只有最外层才会接触Repository的具体实现
        StudentRepoImpl studentRepoImpl = new StudentRepoImpl();
        // 把实现类注入到UseCase中
        StudentUseCase studentUseCase = new StudentUseCase(studentRepoImpl);

        // 所有业务操作都通过UseCase来完成,完全不碰Repository
        Student newStudent = new Student("1001", "李小明");
        studentUseCase.createStudent(newStudent);

        Student foundStudent = studentUseCase.getStudentById("1001");
        System.out.println("查询到学生:" + foundStudent.getName());
    }
}

这么做的核心好处

  • 符合清洁架构依赖规则:domain和usecase层完全不依赖adapter层,以后如果要换Repository实现(比如从JDBC换成MongoDB),只需要写个新的StudentRepo实现类,UseCase和domain层一行代码都不用改。
  • 职责单一:UseCase管业务逻辑,Repository只管数据访问,代码分工明确,后期维护起来太省心了。
  • 测试友好:测试UseCase的时候,不用搭真实数据库,直接用Mock框架(比如Mockito)造一个StudentRepo的假实例,就能单独测试业务逻辑,速度快还稳定。

一定要避开的坑

绝对不要在domain或者usecase的代码里import adapter层的类(比如StudentRepoImpl),一旦这么做,就打破了清洁架构的依赖边界,内层依赖了外层,后期的扩展性直接就没了。


内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.08 12:53:00