用java快速实现一个六边形架构的例子

图片.png

您是否遇到过将业务逻辑与UI或者n层体系结构中的其他方法混合在一起的混乱代码?您是否曾经也遇到过这样的问题,当你在测试业务逻辑的时候并没有将应用程序和数据库隔离开来?幸运的是,Hexagonal Architecture(例如:端口和适配器架构,此名称将在此后通过本教程使用)来可以帮助你解决问题。

Loyalty应用

现在,让我们以一个例子来开始Ports&Adapters旅程。我们正在构建一个客户忠诚度(loyalty)应用程序,该应用程序能够注册客户,升级和降级客户状态。

这个应用程序由三个组成部分。第一个组件appcore是整个应用程序的核心,主要包括业务领域对象和业务逻辑的实现。appcore组件无法单独执行任何操作。然后,第二个组件是command-console-adapter他主要是接收请求并通过命令行控制台驱动appcore组件中的所有业务方法。 最后一个组件inmemory-repository-adapter作为内存数据存储解决方案,它处理所有与数据存储相关的方法。此组件提供来自appcore的调用,并相应地提供响应。

Application Core(应用核心)

该组件代表整个架构的业务核心。然后定义端口,在架构上下文中,端口表示对不同的业务案例提供对应的扩展和支持。在大多数语言中,可以把他理解成是一个接口(因为接口具有多态能力)。

初始化和驱动业务核心的端口是主端口。来自业务核心调用的服务和响应端口是辅助端口。

在我们的例子中,CustomerService接口就是主端口,CustomerRepository接口是辅助端口。我们可以看到端口通常是业务核心组件的一部分,如本例中的appcore。

CustomerRepository接口有关于数据存储相关的方法:

package com.codespeaks.hexagonal.repository;
import java.util.List;
import java.util.Optional;
import com.codespeaks.hexagonal.domain.Customer;
import com.codespeaks.hexagonal.exception.CustomerNotFoundException;

public interface CustomerRepository {
    public Customer CreateCustomer(Customer customer);
    public Customer UpdateCustomer(Customer customer) throws CustomerNotFoundException;
    public List findAll();
    public Optional findCustomerById(int customerId);
}

然后,CustomerService接口暴露所有业务方法:

package com.codespeaks.hexagonal.service;
import java.util.List;
import java.util.Optional;
import com.codespeaks.hexagonal.domain.Customer;
import com.codespeaks.hexagonal.exception.CustomerNotFoundException;
public interface CustomerService {
    public Customer registerCustomer(Customer customer);
    public Customer upgradeCustomer(Customer customer) throws CustomerNotFoundException;
    public Customer downgradeCustomer(Customer customer) throws CustomerNotFoundException;
    public List getAllCustomers();
    public Optional findCustomerById(int customerId);
}

内存Repository 适配器

在端口&适配器架构中他是一个适配器组件。适配器表示端口的实现,以满足不同的业务需求。有时,它可能只是一个简单的实现接口的类。有时,它可能是涉及第三方服务的库的集合。根据适配器实现的端口,我们还有主适配器和辅助适配器。

在组件inmemory-repository-adapter中,类InMemoryCusotmerRepositoryImpl实现接口CustomerRepository。他为组件appcore提供内存中数据操作调用,因此它是辅助适配器。

命令控制台适配器

这是本示例中的另一个适配器组件:命令控制台适配器。它包含CommandInterface接口以与命令控制台的输入进行交互:

package com.codespeaks.hexagonal.adapter.console;
import java.util.Scanner;
public interface CommandInterface {
    public void list(Scanner scanner);
    public void register(Scanner scanner);
    public void upgrade(Scanner scanner);
    public void downgrade(Scanner scanner);
    public void info();
}

虽然端口通常被描述为接口,但这个组件中的接口CommandInterface根本不是端口。从架构的角度来看,组件整体代表适配器。通过它的实现CommandInterfaceImpl,它使CustomerService适应命令控制台操作。

该适配器组件是主适配器,因为它通过主端口CustomerService驱动整个应用程序。

总结:

如示例所示,端口和适配器之间的边界很清晰。业务逻辑不会透过业务核心边界并泄漏到周围适配器,反过来也是一样的。

要添加Web展示端与业务核心进行交互,我们可以通过创建另一个适配器组件web-ui-apdater来实现此目标。 因此,它对任何其他现有代码逻辑没有影响。我们还可以为事件通知定义新端口和各种适配器实现,并记录日志以满足业务需求。

它还有益于对业务核心组件和任何适配器的集成测试。可以使用子实现来轻松替换每个相关组件,以便可以轻松地测试任何组件。

代码例子在: https://github.com/letcodespeak/hexagonal-architecture

你可能感兴趣的:(用java快速实现一个六边形架构的例子)