Golang领域模型

前言: 六边形架构又称“端口适配器架构”,实际上也是一种分层架构,只不过由上下或者左右变成了内部与外部。其核心理念就是应用通过端口与外部进行交互的。核心的业务逻辑(领域模型)与外部资源(数据库等资源)完全隔离,仅通过适配器进行交互,解决了业务逻辑与用户数据交错的问题,很好的实现了前后端分离。

困惑:

  • 在分层架构中是否困惑过某些逻辑处理或某些数据处理该放在哪一层?
  • 在分层架构中是否困惑过该分多少层?
  • 在分层架构中是否困惑过平层和跨层调用是否合理?

六边形架构

Alistair Cockburn 提出了一种具有对称特征的架构风格。在这种架构中,不同的客户通过平等的方式与系统交互。比如HTTP客户,MQ客户,它们平等对系统提供输入。RedisDB也平等的提供输出。每个客户都拥有自己的适配器,去理解输入,比如ginirisecho就是http的适配器。那么内部是业务系统(领域模型),外部就是输入和输出的适配器。重心放在内部业务逻辑上,隔离输入和输出。如果非要用分层来理解,那么六边形分为内层和外层。

Alistair Cockburn提出的六边形是有Application和Domain的,但现在微服务体系下Application已经没有存在的必要了,一个微服务就是一个Application

那么六边形和DDD的结合是如何应对上述困惑的。所有数据处理全部由repository适配成实体,逻辑都是领域服务、聚合、实体的行为。分多少层和平层、跨层调用本身也不存在。

项目目录

  • domain - 领域模型

    • aggregate - 聚合
    • entity - 实体
    • dto - 传输对象
    • po - 持久化对象
    • *.go - 领域服务
  • adapter - 端口适配器
    • controller - 输入适配器
    • repository - 输出适配器
  • server - 服务端程序入口
    • conf - 配置文件
    • main.go - 主函数
  • infra - 基础设施
    • *go - 基础设施组件

domain 领域模型目录

对应六边形的内部,主要放领域服务service的代码。子目录分为aggregate聚合根目录、entity实体目录。dto子目录是外部输入输出对象。po子目录是数据库的持久化对象,这些对象是生成的。

adapter 适配器目录

对应六边形的外部,主要是输入和输出的适配器。controller子目录负责httpapi输入,repository子目录负责实体的读写。

外部adapter目录下的controllerrepository依赖内部的domain相关,那么domain要使用repository处理po的读写呢?这样不就互相依赖了吗?后续会篇幅依赖倒置讲解如何外部依赖内部,内部依赖抽象。

代码示例

package controller import ( domain 'github.com/8treenet/freedom/example/fshop/domain' ) type Cart struct { Worker freedom.Worker CartSev *domain.Cart //购物车领域服务,依赖注入 } // GetItems 获取购物车商品列表, GET: /cart/items route. func (c *Cart) GetItems() freedom.Result { userId, err := c.Worker.IrisContext().URLParamInt('userId') if err != nil { return &infra.JSONResponse{Error: err} } //适配http的输入参数userId后调用领域模型目录的入口领域服务 dto, err := c.CartSev.Items(userId) if err != nil { return &infra.JSONResponse{Error: err} } return &infra.JSONResponse{Object: dto} }

  • 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
  • 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
package domain

import (
   //引用仓库
'github.com/8treenet/freedom/example/fshop/adapter/repository'
'github.com/8treenet/freedom/example/fshop/domain/aggregate'
)
func init() {
freedom.Prepare(func(initiator freedom.Initiator) {
//绑定创建领域服务函数到框架,框架会根据客户的使用做依赖倒置和依赖注入的处理。
initiator.BindService(func() *Cart {
//创建 Cart领域服务
return &Cart{}
})
//控制器客户使用需要明确使用 InjectController
initiator.InjectController(func(ctx freedom.Context) (service *Cart) {
initiator.GetService(ctx, &service)
return
})
})
}

// Cart 购物车领域服务.
type Cart struct {
CartRepo    repository.CartRepo     //购物车仓库,这里是依赖倒置的
}

// Items 购物车全部商品项
func (c *Cart) Items(userId int) (items dto.CartItemRes, e error) {
    // 使用 c.CartRepo读取购物车数据
return
}

// DeleteAll 清空购物车
func (c *Cart) DeleteAll(userId int) (e error) {
return c.CartRepo.DeleteAll(userId)
}
  • 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
  • 35
  • 36
  • 37
  • 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
  • 35
  • 36
  • 37

目录

  • golang领域模型-开篇
  • golang领域模型-六边形架构
  • golang领域模型-实体
  • golang领域模型-资源库
  • golang领域模型-依赖倒置
  • golang领域模型-聚合根
  • golang领域模型-CQRS
  • golang领域模型-领域事件

项目代码 https://github.com/8treenet/freedom/tree/master/example/fshop

PS:关注公众号《从菜鸟到大佬》,发送消息“加群”或“领域模型”,加入DDD交流群,一起切磋DDD与代码的艺术!

(0)

相关推荐

  • 领域驱动设计(DDD)在爱奇艺打赏业务的实践

    领域驱动设计(Domain-Driven Design,以下简称DDD)思潮的形成要追述到30几年前,17年前,Eirc Evans定义了领域驱动设计的概念.DDD一直为传统行业的软件工程师提供软件设 ...

  • DDD 领域驱动设计简单介绍

    不同于其它的架构方法,领域驱动设计DDD(Domain Driven Design)提出了从业务设计到代码实现一致性的要求,不再对分析模型和实现模型进行区分.也就是说从代码的结构中我们可以直接理解业务 ...

  • 走向卓越,领域驱动设计的思维方式

    软件系统是以特定的代码解决现实世界的复杂问题.软件开发的最大困难就是应对复杂度,复杂度可能来源于各个方面.领域驱动设计的概念是 2004 年 Evic Evans 提出的 Domain-Driven ...

  • 领域驱动设计(DDD)理论与方法

    DDD由来与优势 软件架构设计的真正目的是解决软件复杂度带来的问题,软件复杂度由来主要由三方面:高并发场景下的对软件高性能要求.业务场景对软件高可用要求.持续变化的业务以及业务扩张和增加需求对软件扩展 ...

  • (49条消息) 阿里技术专家详解DDD系列 第二弹

    阿里加多 2019-10-20 10:17:08 3936 收藏 8 版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明. 本文链接:https:/ ...

  • 真的醉了!GitHub标星1w的安卓架构师必备技能,成功入职阿里

    写在前面 记得我大二时"不务正业"地自学Android并跟了老师做项目,到大三开始在目前的公司实习,至今毕业已有几年多,学习Android已经6.7年多了!但总感觉知识点很零散,并 ...

  • DDD之代码架构

    荒腔走板 这是一篇迟到的文章.这其实是我写DDD的第四篇文章.去年11月份左右我在个人网站上写了三篇关于DDD的文章,都是比较偏战略部分的.那个时候我还在一个正在使用DDD的项目上,也是我第一次真正开 ...

  • 解读六边形架构

    追溯微服务架构的渊源,一般会涉及到六边形架构.追溯六边形架构的起源,要看始作俑者Alistair Cockburn的这篇文章 http://alistair.cockburn.us/Hexagonal ...

  • Golang有什么优势?GO语言入门!

    虽然Erlang和Golang同属于编程语言,但是很多人对它们的了解并不是很多,甚至有人觉得Erlang和Golang有着很大的联系,那么Erlang和Golang有什么区别呢? Erlang和Gol ...

  • RabbitMQ Golang教程(三)

    RabbitMQ Golang教程(三) 什么是发布/订阅? 创建一个队列每个任务只传递给一个工人,做些不同的事,向多个消费者传递一个消息.这就是所谓的"订阅/发布模式". 构建一 ...

  • RabbitMQ Golang教程(二)

    RabbitMQ Golang教程(二) 任务队列 什么是任务队列 ? 把要执行的任务放在队列中.使用较多的任务队列有machiney.Celery.goWorker.YTask.每一个任务队列都有自 ...

  • Python在大部分领域都能胜任,为什么很多企业转向了Golang?

    或许很多人会说,性能在大多数情况下并非问题,我也这么认为,要不然就没有那么多流行的动态语言了.虽然,性能的确是一个很重要的考虑因素,但是当因性能而严重降低了项目的开发进度,也得不偿失,特别是初创企业. ...

  • 基于golang的redis使用

    基于golang的redis使用 下载package go get github.com/garyburd/redigo/redis redis 在使用中.会涉及到set.Mset.expire.lp ...

  • 基于golang实现的redis连接池

    基于golang实现的redis连接池 代码篇: package mainimport ( "fmt" "github.com/garyburd/redigo/redis ...

  • RabbitMQ Golang教程

    RabbitMQ Golang教程 首先,使用go get安装amqp go get github.com/streadway/amqp 发送 我们将消息发布者(发送者)称为 send.go,将消息消 ...

  • 基于golang分布式爬虫系统的架构体系v1.0

    基于golang分布式爬虫系统的架构体系v1.0 一.什么是分布式系统 分布式系统是一个硬件或软件组件分布在不同的网络计算机上,彼此之间仅仅通过消息传递进行通信和协调的系统.简单来说就是一群独立计算机 ...

  • [Go]Golang 1.16 中 Modules的主要变化更新

    本文转载,目的方便查阅 01介绍 Golang 1.16 已经正式发布了,其中 Modules 有一些变化: 默认开启 Modules. 不自动修改 go.mod 和 go.sum. 通过指定 @ve ...