当前位置: 首页 > news >正文

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


业务场景:用户登录

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

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

方式一:传统MVC架构

// ==================== 1. Controller层 ====================
@RestController
public class UserController {@Autowiredprivate 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 {@Autowiredprivate UserMapper userMapper; // :依赖Mapper接口@Autowiredprivate PasswordEncoder passwordEncoder; // 依赖加密组件@Overridepublic 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架构(依赖倒置)

// ==================== 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@Autowiredprivate UserMapper userMapper;@Overridepublic User findByUsername(String username) {// 调用MyBatis Mapper执行SQLreturn userMapper.selectByUsername(username);}
}/*** EncryptionService的实现 - 在基础设施层* 作用:用Spring Security技术实现密码加密*/
@Component  
public class BCryptEncryptionService implements EncryptionService {@Autowiredprivate PasswordEncoder passwordEncoder;@Overridepublic boolean matches(String rawPassword, String encodedPassword) {// 调用Spring Security的密码验证return passwordEncoder.matches(rawPassword, encodedPassword);}
}// ==================== 4. Controller层 ====================
@RestController
public class LoginController {@Autowiredprivate UserLoginService userLoginService; // 依赖领域服务@PostMapping("/login")  public User login(@RequestBody LoginRequest request) {// Controller直接调用领域服务return userLoginService.login(request.getUsername(), request.getPassword());}
}

依赖关系:

Controller → UserLoginService → UserRepository接口 ← 实现 ← MyBatisUserRepository→ EncryptionService接口 ← 实现 ← BCryptEncryptionService

核心区别总结

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

问题

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

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

传统MVC的问题:

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

DDD的改进:

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

核心思想:

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

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

http://www.dtcms.com/a/593617.html

相关文章:

  • 【LeetCode刷题】移动零
  • 江苏省建设厅网站公示腾讯企业邮箱注册申请官网
  • 本地部署 Stable Diffusion3.5!cpolar让远程访问很简单!
  • UE_ControllRig交互
  • Swift-snapKit使用
  • Hello-Agents第二章深度解析:智能体的进化之路——从符号逻辑到AI原生
  • 51单片机汇编实现DHT11读取温湿度
  • LiveCharts.Wpf 控件的使用
  • 柔性软风管-测量统计一键出量
  • 告别手动录财报!财务报表OCR识别解决方案选型指南
  • (128页PPT)智慧化工厂区一体化管理平台建设方案(附下载方式)
  • jsp网站建设项目实战总结怎么做网站统计
  • 【Rust 探索之旅】Rust 全栈 Web 开发实战:从零构建高性能实时聊天系统
  • 【Rust 探索之旅】Tokio 异步运行时完全指南:深入理解 Rust 异步编程与源码实现
  • 个人网站做经营性crm销售管理系统功能
  • Ubuntu 22.04 Docker 安装指南
  • C++基础语法篇二 ——引用、内联和空指针
  • 有没有做兼职的好网站十堰网络公司排名
  • vscode中claude code插件代理地址设置
  • 网页制作与网站管理在线销售管理系统
  • 如何使用 vxe-table 实现右键菜单异步权限控制
  • 11月10日学习总结--初识numpy
  • 前后端通信加解密(Web Crypto API )
  • 基于数字图像相关(DIC)技术的机械臂自动化焊接残余应力全场变形高精度测量
  • XTOM-TRANSFORM-ROB:面向大尺寸构件的移动式非接触三维扫描与自动化质量检测
  • PyWinInspect:pywinauto 桌面自动化开发伴侣,集成 Inspect 元素检查 + 定位代码自动生成,效率大提升!
  • 个人做什么网站软件技术专升本难吗
  • HarmonyOS:ArkUI栅格布局系统(GridRow/GridCol)
  • 电商设计师常用的网站wordpress 获取分类地址
  • 开放签电子签章系统3.2版本更新内容