六边形架构:核心与出站适配器的依赖关系存疑
六边形架构:业务逻辑调用适配器却不依赖它的原因
这两点完全不矛盾,核心是依赖倒置原则在六边形架构里的具体应用,拆解来看就清楚了:
业务逻辑调用的是「抽象端口」,而非具体的适配器实现
业务逻辑会根据自身需求定义抽象接口(比如数据持久化需要的保存用户、查询用户方法),这个接口属于架构的核心层,完全不涉及任何外部技术细节(比如MySQL、Redis、第三方API)。业务逻辑的代码里只会引用这个抽象接口,不会直接写任何和适配器相关的代码。出站适配器是抽象端口的实现者,它依赖业务逻辑的定义
适配器是用来对接外部系统的具体实现,比如MySQL适配器、Redis适配器,它们必须遵守业务逻辑定义的抽象接口规范——也就是说,适配器要实现核心层的抽象接口,所以是适配器依赖业务逻辑的抽象,而非反过来。调用关系的本质是「依赖注入」
运行时,通过依赖注入(DI)把具体的适配器实例传给业务逻辑组件。业务逻辑里的userRepository.save(user)看起来是在调用适配器,但实际上调用的是抽象方法,具体执行哪个适配器的逻辑,完全由外部注入的实例决定。业务逻辑本身根本不知道也不关心具体是MySQL还是Redis适配器,自然也就不依赖适配器。
举个伪代码例子更直观:
核心业务层(抽象定义)
// 业务逻辑自己定义的抽象端口,属于核心层 interface UserRepository { void save(User user); } // 业务逻辑服务,只依赖抽象端口 class UserService { private UserRepository repo; // 构造注入,依赖的是抽象,不是具体实现 public UserService(UserRepository repo) { this.repo = repo; } public void createUser(User user) { // 先做业务校验、处理 if (user.getAge() < 18) { throw new IllegalArgumentException("未成年无法注册"); } // 调用抽象方法,和具体适配器无关 repo.save(user); } }
出站适配器层(具体实现)
// MySQL适配器,实现核心层的抽象接口,依赖核心层的定义 class MySQLUserRepoAdapter implements UserRepository { @Override public void save(User user) { // 具体的MySQL持久化逻辑 executeSQL("INSERT INTO users(id, name) VALUES(?, ?)", user.getId(), user.getName()); } } // Redis适配器,同样实现核心层的抽象接口 class RedisUserRepoAdapter implements UserRepository { @Override public void save(User user) { // 具体的Redis缓存逻辑 redisClient.set("user:" + user.getId(), serialize(user)); } }
这样设计的好处很明显:如果后续要把持久化从MySQL换成Redis,只需要写一个新的适配器实现UserRepository,业务逻辑代码完全不需要修改——这就是六边形架构“业务逻辑不依赖外部细节”的核心优势。
内容的提问来源于stack exchange,提问作者Mandroid
相关产品推荐
相关产品推荐

