接口在领域层,实现在基础设施层


业务场景:用户登录

假设我们有一个简单的用户登录功能:

  • 用户输入用户名密码
  • 验证用户名密码是否正确
  • 登录成功后返回用户信息

方式一:传统MVC架构

java 复制代码
// ==================== 1. Controller层 ====================
@RestController
public class UserController {
    
    @Autowired
    private UserService userService; // 依赖Service
    
    /**
     * 处理用户登录请求
     */
    @PostMapping("/login")
    public User login(@RequestBody LoginRequest request) {
        // Controller只负责接收请求和返回响应
        return userService.login(request.getUsername(), request.getPassword());
    }
}

// ==================== 2. Service层 ====================
// Service接口
public interface UserService {
    User login(String username, String password);
}

// Service实现
@Service  
public class UserServiceImpl implements UserService {
    
    @Autowired
    private UserMapper userMapper; // :依赖Mapper接口
    
    @Autowired
    private PasswordEncoder passwordEncoder; // 依赖加密组件
    
    @Override
    public User login(String username, String password) {
        // 1. 查询数据库
        User user = userMapper.selectByUsername(username);
        
        // 2. 验证用户是否存在
        if (user == null) {
            throw new RuntimeException("用户不存在");
        }
        
        // 3. 验证密码是否正确
        if (!passwordEncoder.matches(password, user.getPassword())) {
            throw new RuntimeException("密码错误");
        }
        
        // 4. 返回用户信息
        return user;
    }
}

// ==================== 3. Mapper层 ====================
// Mapper接口
public interface UserMapper {
    User selectByUsername(String username);
}

// Mapper实现(由MyBatis自动生成)
// 这个实现会真正执行SQL:SELECT * FROM users WHERE username = ?

依赖关系:

复制代码
Controller → UserService接口 → UserServiceImpl → UserMapper接口 → 数据库

方式二:DDD架构(依赖倒置)

java 复制代码
// ==================== 1. 领域层(核心业务) ====================
// 领域层定义:我需要什么能力?(不关心如何实现)

/**
 * 用户仓储接口 - 在领域层定义
 * 作用:领域层说"我需要从某个地方获取用户数据"
 */
public interface UserRepository {
    /**
     * 根据用户名查找用户
     */
    User findByUsername(String username);
}

/**
 * 加密服务接口 - 在领域层定义  
 * 作用:领域层说"我需要密码加密验证的能力"
 */
public interface EncryptionService {
    /**
     * 验证密码是否匹配
     */
    boolean matches(String rawPassword, String encodedPassword);
}

// ==================== 2. 领域服务 ====================
/**
 * 用户登录领域服务
 * 作用:实现纯粹的业务逻辑
 */
@Service
public class UserLoginService {
    
    // ✅ 关键:依赖自己定义的接口,不依赖具体实现
    private final UserRepository userRepository;
    private final EncryptionService encryptionService;
    
    public UserLoginService(UserRepository userRepo, EncryptionService encryptionService) {
        this.userRepository = userRepo;
        this.encryptionService = encryptionService;
    }
    
    /**
     * 执行用户登录业务逻辑
     */
    public User login(String username, String password) {
        // 1. 查询用户(调用接口,不关心数据从哪里来)
        User user = userRepository.findByUsername(username);
        
        // 2. 业务验证:用户是否存在
        if (user == null) {
            throw new RuntimeException("用户不存在"); // 业务异常
        }
        
        // 3. 业务验证:密码是否正确  
        if (!encryptionService.matches(password, user.getPassword())) {
            throw new RuntimeException("密码错误"); // 业务异常
        }
        
        // 4. 返回用户信息
        return user;
    }
}

// ==================== 3. 基础设施层(技术实现) ====================
/**
 * UserRepository的实现 - 在基础设施层
 * 作用:用MyBatis技术实现数据访问
 */
@Repository
public class MyBatisUserRepository implements UserRepository {
    
    // 这里可以使用MyBatis的Mapper
    @Autowired
    private UserMapper userMapper;
    
    @Override
    public User findByUsername(String username) {
        // 调用MyBatis Mapper执行SQL
        return userMapper.selectByUsername(username);
    }
}

/**
 * EncryptionService的实现 - 在基础设施层
 * 作用:用Spring Security技术实现密码加密
 */
@Component  
public class BCryptEncryptionService implements EncryptionService {
    
    @Autowired
    private PasswordEncoder passwordEncoder;
    
    @Override
    public boolean matches(String rawPassword, String encodedPassword) {
        // 调用Spring Security的密码验证
        return passwordEncoder.matches(rawPassword, encodedPassword);
    }
}

// ==================== 4. Controller层 ====================
@RestController
public class LoginController {
    
    @Autowired
    private UserLoginService userLoginService; // 依赖领域服务
    
    @PostMapping("/login")  
    public User login(@RequestBody LoginRequest request) {
        // Controller直接调用领域服务
        return userLoginService.login(request.getUsername(), request.getPassword());
    }
}

依赖关系:

复制代码
Controller → UserLoginService → UserRepository接口 ← 实现 ← MyBatisUserRepository
                              → EncryptionService接口 ← 实现 ← BCryptEncryptionService

核心区别总结

方面 传统MVC DDD方式
接口定义位置 Service层定义业务接口 Mapper层定义数据接口 领域层定义业务需求接口
Service依赖什么 UserMapper(数据访问接口) UserRepository(业务数据接口) EncryptionService(业务能力接口)
业务逻辑位置 Service实现中,与技术代码混合 领域服务中,纯业务逻辑
技术实现位置 Service中直接使用技术组件 基础设施层实现领域接口
可测试性 需要mock数据库、加密组件 只需mock业务接口
变更影响 换加密算法要改Service代码 换加密算法只需换基础设施实现

问题

"传统mvc架构下不是还有mapper层吗,依赖mapper层的接口呀。"

传统MVC确实有Mapper层接口,但关键区别在于:

传统MVC的问题:

java 复制代码
// Service直接依赖数据访问技术
public class UserServiceImpl {
    private UserMapper userMapper; // 依赖MyBatis的Mapper
    
    public User login(...) {
        User user = userMapper.selectByUsername(...); // 直接数据操作
        // 业务逻辑与数据访问深度耦合
    }
}

DDD的改进:

java 复制代码
// 领域服务依赖业务接口,不依赖具体技术
public class UserLoginService {
    private UserRepository userRepository; // 依赖业务接口
    
    public User login(...) {
        User user = userRepository.findByUsername(...); // 业务语义操作
        // 纯业务逻辑,不知道底层用MyBatis还是JPA
    }
}

核心思想:

  • 传统MVC:Service → Mapper接口(仍然依赖具体的数据访问技术)
  • DDD:领域服务 → 业务接口 ← 基础设施实现(业务层完全与技术解耦)

这样做的最大好处是:当需要更换数据库技术(比如从MySQL换到MongoDB)时,传统MVC要修改Service代码,而DDD只需要换一个基础设施实现,领域层完全不用动!

相关推荐
奔跑的架构师7 小时前
[A-50]ARMv9/v8-DVFS系统架构
linux·arm开发·架构·系统架构·arm
跨境数据猎手8 小时前
参考pandabuy淘宝代购与集运系统架构设计
系统架构·团队开发
AI产品测评官9 小时前
从L3寻源智能体到全链路闭环ATS:拆解世纪云猎新一代AI招聘系统架构
人工智能·系统架构
奔跑吧树袋熊17 小时前
多租户隔离该做到哪一层:从连接池到 ORM 的取舍
开发语言·数据库·oracle·系统架构
励志不掉头发的内向程序员19 小时前
【LibreCAD 2D架构】从 addHistory 到 RS_UndoCycle:LibreCAD 里的两套 History 与撤销机制
开发语言·c++·qt·学习·系统架构
XiaoZhenHua9820 小时前
C#工业机器视觉软件架构设计:从能运行的Demo到能够稳定跑产线的软件
计算机视觉·系统架构·自动化
XiaoZhenHua9820 小时前
C# WinForms + 西门子S7 + SQLite + EPPlus生产数据采集系统架构设计
系统架构·sqlite·c#
粉色大象21 小时前
handdrawn‑architecture‑video:开源SVG架构图转手绘4K动画视频|本地AI Agent Skill
人工智能·ai·ai作画·系统架构·开源·aigc·音视频
微三云 - 廖会灵 (私域系统开发)1 天前
私域团购系统架构设计:五级定价、自动结算与三级合规的技术实现
系统架构
木木学AI1 天前
2026主流大模型电话机器人系统解析:技术架构、业务执行与企业落地实践
架构·系统架构·机器人