8

番茄架构:一种遵循常识宣言的软件架构方法

 1 year ago
source link: https://www.jdon.com/66527.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

番茄架构:一种遵循常识宣言的软件架构方法

番茄(tomato)架构是一种遵循常识宣言的软件架构方法:

1、将业务逻辑执行与输入源(Web 控制器、消息监听器、计划作业等)分开
Web 控制器、消息监听器、计划作业等输入源应该是一个薄层,从请求中提取数据并将实际业务逻辑执行委托给“应用程序核心”。

不要这样做:

@RestController
class CustomerController {
    private final CustomerService customerService;
    
    @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 {
    private final CustomerService customerService;
    
    @PostMapping("/api/customers")
    void createCustomer(@RequestBody Customer customer) {
       customerService.save(customer);
    }
}

@Service
@Transactional
class CustomerService {
   private final CustomerRepository customerRepository;

   void save(Customer customer) {
      if(customerRepository.existsByEmail(customer.getEmail())) {
         throw new EmailAlreadyInUseException(customer.getEmail());
      }
      customer.setCreateAt(Instant.now());
      customerRepository.save(customer);
   }
}

使用这种方法,无论您是尝试从 REST API 调用还是从 CLI 创建客户,所有业务逻辑都集中在 Application Core应用程序核心 中。

2、不要让“外部服务集成”对“应用程序核心”的影响太大
从应用程序核心中,我们可以与数据库、消息代理或第 3 方 Web 服务等进行对话。必须注意业务逻辑执行者不要严重依赖外部服务集成。

例如,假设您正在使用 Spring Data JPA 进行持久化,并且您希望使用分页从CustomerService获取客户。

不要这样做

@Service
@Transactional
class CustomerService {
   private final CustomerRepository customerRepository;

   PagedResult<Customer> getCustomers(Integer pageNo) {
      Pageable pageable = PageRequest.of(pageNo, PAGE_SIZE, Sort.of("name"));
      Page<Customer> cusomersPage = customerRepository.findAll(pageable);
      return convertToPagedResult(cusomersPage);
   }
}

相反,这样做

@Service
@Transactional
class CustomerService {
   private final CustomerRepository customerRepository;

   PagedResult<Customer> getCustomers(Integer pageNo) {
      return customerRepository.findAll(pageNo);
   }
}

@Repository
class JpaCustomerRepository {

   PagedResult<Customer> findAll(Integer pageNo) {
      Pageable pageable = PageRequest.of(pageNo, PAGE_SIZE, Sort.of("name"));
      return ...;
   }
}

这样,任何持久性库更改都只会影响存储库层。

3、将领域逻辑保留在领域对象中
有影响领域对象状态更改方法或从对象状态计算某些内容的方法,则将这些方法放入该域对象。

不要这样做

class Cart {
    List<LineItem> items;
}

@Service
@Transactional
class CartService {

   CartDTO getCart(UUID cartId) {
      Cart cart = cartRepository.getCart(cartId);
      BigDecimal cartTotal = this.calculateCartTotal(cart);
      ...
   }
   
   private BigDecimal calculateCartTotal(Cart cart) {
      ...
   }
}

相反,这样做:

class Cart {
    List<LineItem> items;

   public BigDecimal getTotal() {
      ...
   }
}

@Service
@Transactional
class CartService {

   CartDTO getCart(UUID cartId) {
      Cart cart = cartRepository.getCart(cartId);
      BigDecimal cartTotal = cart.getTotal();
      ...
   }
}

如果他们称我为遵循此架构的“代码猴子”怎么办?
别理他们。专注于提供业务价值。



About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK