如何将业务逻辑与交付机制分离:Tomato Architecture的7个关键设计模式
【免费下载链接】tomato-architectureTomato Architecture - A common sense driven approach to software architecture项目地址: https://gitcode.com/gh_mirrors/to/tomato-architecture
在现代软件开发中,Tomato Architecture提供了一种基于常识的软件架构方法,特别强调将业务逻辑与交付机制分离的重要性。这种架构设计模式帮助开发者构建更灵活、可维护的应用程序,无论您是从Web控制器、CLI命令行还是调度任务调用业务逻辑,都能保持核心代码的一致性。
🍅 什么是Tomato Architecture?
Tomato Architecture是一种实用主义的软件架构方法,遵循"常识宣言"原则。它的核心理念是:将业务逻辑与交付机制完全分离,让应用核心独立于任何调用上下文。
从上图可以看出,Tomato Architecture清晰地划分了不同的关注点:
- 应用核心:包含所有业务逻辑和领域规则
- 交付机制:Web控制器、CLI命令、调度任务等
- 外部服务集成:数据库、消息队列、第三方API
🔑 7个关键设计模式
1. 按功能打包,而非按技术层打包
传统的MVC架构通常按技术层(控制器、服务、存储库)组织代码,而Tomato Architecture建议按业务功能打包。如果您正在构建微服务或模块化单体应用,这种按功能打包的方式能更好地反映业务领域。
为什么这样做?
- 更容易理解和维护相关功能
- 减少模块间的耦合
- 促进代码重用和测试
2. 保持"应用核心"独立于交付机制
应用核心应该暴露可以通过main()方法调用的API。这意味着应用核心不应该依赖任何HTTP/Web层库,也不应该包含任何调度逻辑或CLI命令执行逻辑。
实现要点:
- 应用核心只关注业务规则
- 交付机制负责数据提取和结果呈现
- 两者通过清晰的接口通信
3. 分离业务逻辑执行与输入源
Web控制器、消息监听器、调度任务等输入源应该是一个薄层,仅负责从请求中提取数据,然后将实际业务逻辑执行委托给"应用核心"。
错误做法示例:
@RestController class CustomerController { @PostMapping("/api/customers") void createCustomer(@RequestBody Customer customer) { // 业务逻辑直接写在控制器中 if(customerService.existsByEmail(customer.getEmail())) { throw new EmailAlreadyInUseException(customer.getEmail()); } customer.setCreateAt(Instant.now()); customerService.save(customer); } }正确做法:
@RestController class CustomerController { @PostMapping("/api/customers") void createCustomer(@RequestBody Customer customer) { // 控制器只负责调用服务层 customerService.save(customer); } } @Service @Transactional class CustomerService { void save(Customer customer) { // 业务逻辑集中在服务层 if(customerRepository.existsByEmail(customer.getEmail())) { throw new EmailAlreadyInUseException(customer.getEmail()); } customer.setCreateAt(Instant.now()); customerRepository.save(customer); } }4. 不要让"外部服务集成"过度影响"应用核心"
从应用核心访问数据库、消息代理或第三方Web服务时,必须注意业务逻辑执行器不应严重依赖外部服务集成。
分层设计的好处:
- 数据库层变化只影响存储库层
- 业务逻辑层保持稳定
- 更容易替换外部依赖
5. 将领域逻辑保留在领域对象中
如果领域对象有状态变更方法或基于对象状态的计算方法,这些方法应该属于该领域对象本身。
领域对象示例:
class Cart { List<LineItem> items; public BigDecimal getTotal() { // 购物车总价计算逻辑属于领域对象 return items.stream() .map(item -> item.getPrice().multiply(item.getQuantity())) .reduce(BigDecimal.ZERO, BigDecimal::add); } }6. 避免不必要的接口
不要因为"将来可能需要另一个实现"而创建接口。如果那一天真的到来,现代IDE可以轻松提取接口。对于测试,可以使用Mockito等模拟库来模拟类,而不需要实现接口。
7. 充分利用框架的能力和灵活性
选择的库和框架是为了解决大多数应用程序的常见需求而创建的。应该充分利用所选框架的功能和灵活性,而不是在其之上创建间接层或抽象层。
🚀 实践指南
快速开始Tomato Architecture
要应用Tomato Architecture,请遵循以下步骤:
- 识别业务功能:将应用程序分解为独立的业务功能模块
- 定义应用核心:为每个功能创建独立的业务逻辑层
- 创建薄交付层:Web控制器、CLI命令等应该尽可能薄
- 隔离外部依赖:通过适配器模式处理外部服务集成
- 编写集成测试:测试整个功能而不仅仅是单元
测试策略
Tomato Architecture强调测试整个功能而不仅仅是单元:
✅单元测试:测试业务逻辑单元,必要时模拟外部依赖 ✅集成测试:使用实际外部依赖(数据库、消息代理)测试整个功能 ✅端到端测试:验证整个功能是否按预期工作
使用Testcontainers等工具可以轻松测试真实依赖,虽然可能需要更多时间,但相比获得的信心,这是微不足道的成本。
📊 架构优势
1. 提高可维护性
- 业务逻辑集中在一个地方
- 更容易理解和修改
2. 增强可测试性
- 业务逻辑可以独立于交付机制进行测试
- 更容易编写自动化测试
3. 提升灵活性
- 轻松添加新的交付机制(如CLI、消息监听器)
- 更容易替换外部依赖
4. 促进团队协作
- 清晰的关注点分离
- 减少代码冲突和合并问题
🎯 适用场景
Tomato Architecture特别适合以下场景:
- 企业级应用程序:需要长期维护和扩展的系统
- 多交付渠道应用:同时支持Web、CLI、API等多种访问方式
- 微服务架构:每个服务可以独立应用Tomato原则
- 遗留系统重构:逐步将业务逻辑与交付机制分离
💡 常见问题解答
Q: 为什么叫"番茄"架构?
A: 如果您能接受"六边形"架构(尽管六边形没有特殊意义),那么也应该能接受"番茄"。毕竟我们有洋葱架构,为什么不能有番茄架构呢?😊
Q: 这种架构会增加复杂性吗?
A: 恰恰相反!通过清晰的关注点分离,Tomato Architecture实际上降低了复杂性。每个部分都有明确的职责,新团队成员更容易理解代码结构。
Q: 如何开始应用这种架构?
A: 从一个小模块开始,逐步重构。首先识别一个独立的业务功能,将其业务逻辑提取到应用核心,然后创建薄的交付层。
🌟 总结
Tomato Architecture提供了一种实用、基于常识的软件架构方法,特别强调将业务逻辑与交付机制分离的重要性。通过遵循这7个关键设计模式,您可以构建更灵活、可维护和可测试的应用程序。
记住,架构的最终目标是交付业务价值,而不是追求完美的理论设计。Tomato Architecture帮助您在复杂性和实用性之间找到平衡点,让您的代码既易于理解又易于维护。
无论您是构建新项目还是重构现有系统,考虑采用Tomato Architecture的原则,您会发现代码质量、团队生产力和系统可维护性都会显著提升!
【免费下载链接】tomato-architectureTomato Architecture - A common sense driven approach to software architecture项目地址: https://gitcode.com/gh_mirrors/to/tomato-architecture
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考