https://www.jianshu.com/p/c2a361c2406c

六边形架构

六边形架构又称“端口和适配器模式”,是Alistair Cockburn提出的一种具有对称性特征的架构风格。在这种架构中,系统通过适配器的方式与外部交互,将应用服务于领域服务封装在系统内部。

六边形架构还是一种分层架构,如上图所示,它被分为了三层:端口适配器、应用层与领域层。而端口又可以分为输入端口输出端口

  • 输入端口
    用于系统提供服务时暴露API接口,接受外部客户系统的输入,并客户系统的输入转化为程序内部所能理解的输入。系统作为服务提供者是对外的接入层可以看成是输入端口。
  • 输出端口
    为系统获取外部服务提供支持,如获取持久化状态、对结果进行持久化,或者发布领域状态的变更通知(如领域事件)。系统作为服务的消费者获取服务是对外的接口(数据库、缓存、消息队列、RPC调用)等都可以看成是输入端口。
  • 应用层
    定义系统可以完成的工作,很薄的一层。它并不处理业务逻辑通过协调领域对象或领域服务完成业务逻辑,并通过输入端口输出结果。也可以在这一层进行事物管理。
  • 领域层
    负责表示业务概念、规则与状态,属于业务的核心。

应用层与领域层的不变性可以保证核心领域不受外部的干扰,而端口的可替换性可以很方便的对接不用的外部系统。

序列图

源码演示

通过一个简单客户信息管理(增删改查)来演示以上叙述中的一些概念。这里使用spring-web实现REST API,通过内存HashMap实现领域对象存储与检索。

新建Customer领域模型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class Customer {
private String id;
private String firstName;
private String lastName;
protected Customer() {
}

public Customer(String id, String firstName, String lastName) {
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
}

public String getId() {
return id;
}

public String getFirstName() {
return firstName;
}

public String getLastName() {
return lastName;
}

public void changeFirstName(String firstName) {
this.firstName = firstName;
}

}

实现应用层服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
@Component
public class CustomerApplication {
private CustomerRepository repository;

@Autowired
public CustomerApplication(CustomerRepository repository) {
this.repository = repository;
}

public void create(CreateCustomerCommand command) {
Customer customer = new Customer(UUID.randomUUID().toString(),
command.getFirstName());
repository.add(customer);
}

public Object fetch(String id) {
return repository.get(id);
}

public void changeFirstName(String id, String firstName) {
Customer customer = repository.get(id);
assert customer != null;
customer.changeFirstName(firstName);
repository.update(customer);
}

public Collection<?> all() {
return repository.all();
}

}

实现输入接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
@RestController
public class CustomerController {

private CustomerApplication application;

@Autowired
public CustomerController(CustomerApplication application) {
this.application = application;
}

@PostMapping("/customer")
public ResponseEntity<Object> create(@RequestParam String firstName) {
application.create(new CreateCustomerCommand(firstName));
return ResponseEntity.ok(null);
}

@GetMapping("/customer/{id}")
public ResponseEntity<Object> get(@PathVariable("id") String id) {
return ResponseEntity.ok(application.fetch(id));
}

@PatchMapping("/customer/{id}")
public ResponseEntity<Object> changeFirstName(@PathVariable("id") String id,
@RequestParam String firstName) {
application.changeFirstName(id, firstName);
return ResponseEntity.ok(null);
}

@GetMapping("/customers")
public ResponseEntity<Object> all() {
return ResponseEntity.ok(application.all());
}

}

定义仓储接口

1
2
3
4
5
6
public interface CustomerRepository {
Customer get(String id);
void add(Customer customer);
void update(Customer customer);
Collection<Customer> all();
}

实现仓储接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
@Component
public class InMemoryCustomerRepository implements CustomerRepository {

Map<String, Customer> customerMap = new ConcurrentHashMap<>();

@Override
public Customer get(String id) {
return customerMap.get(id);
}

@Override
public void add(Customer customer) {
customerMap.put(customer.getId(), customer);
}

@Override
public void update(Customer customer) {
customerMap.put(customer.getId(), customer);
}

@Override
public Collection<Customer> all() {
return Collections.unmodifiableCollection(customerMap.values());
}

}