为了账号安全,请及时绑定邮箱和手机立即绑定

六边形架构入门与实践

标签:
架构

说明

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

  • 架构图

    webp

    每一种外部系统都有一个适配器与之对应,外界通过应用层API与内部交互

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

  • 输入端口
    用于系统提供服务时暴露API接口,接受外部客户系统的输入,并客户系统的输入转化为程序内部所能理解的输入。系统作为服务提供者是对外的接入层可以看成是输入端口。

  • 输出端口
    为系统获取外部服务提供支持,如获取持久化状态、对结果进行持久化,或者发布领域状态的变更通知(如领域事件)。系统作为服务的消费者获取服务是对外的接口(数据库、缓存、消息队列、RPC调用)等都可以看成是输入端口。

  • 应用层
    定义系统可以完成的工作,很薄的一层。它并不处理业务逻辑通过协调领域对象或领域服务完成业务逻辑,并通过输入端口输出结果。也可以在这一层进行事物管理。

  • 领域层
    负责表示业务概念、规则与状态,属于业务的核心。

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

  • 序列图

    webp

    业务处理过程

源码演示

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

  • 新建Customer领域模型

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;
    }

}
  • 定义仓储接口

public interface CustomerRepository {    Customer get(String id);    void add(Customer customer);    void update(Customer customer);    Collection<Customer> all();

}
  • 实现应用层服务

@Componentpublic 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();
    }

}
  • 实现输入接口

@RestControllerpublic 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());
    }

}
  • 实现仓储接口

@Componentpublic 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());
    }

}



作者:核子飞弹
链接:https://www.jianshu.com/p/c2a361c2406c


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消