Golang领域模型开篇,当Go遇上DDD
编辑:业余草
推荐:https://www.xttblog.com/?p=5070
我本身就是一个不太会拒绝的人,这点和雷军相似。最近一周,有网友说要给我投稿,内容见本文。所以,本文是转载的一篇文章,有喜欢的可以深入学习!
前言: 八叉树是一位拥有数十年编程经验,醉心于代码艺术的工程师。freedom
是他结合《实现领域驱动设计》与《六边形架构》两文为一众Gopher打造出最符合DDD战术设计的轮子!
DDD是什么?
领域驱动设计(DDD) 做为一种软件工程的方法论,它可以帮助我们设计高质量的软件,或者说任何工程的设计都需要方法论,不论是城市设计、建筑设计、室内设计。
比如没有方法论的情况下楼是可以盖起来的,或许整个楼道和窗户上挂满了电话线、闭路线、电线?下水道隔三差五就堵了?某一户跳闸了导致整个楼都停电了?那么盖楼前是否有好的方法论去建模呢?
不论任何行业的工程设计都因该使用正确的方法论去设计。任何行业的方法论也离不开八个字分而治之、拥抱变化。如果和城市的设计、建筑的设计相比较,我认为软件的设计会更复杂,软件的迭代和变化周期更快,也意味着我们更需要好的方法论。
字面上的领域模型并不抽象,可以理解为uml
建模中的对象,它有什么属性?它有什么行为?那么就可以把它规划成某个领域的概念。
DDD 是一个分而治之的过程,是一系列分而治之的方法论。
如何把一个公司的领域划分成多个子域,比如教育公司会划分成作业子域、课程子域。电商可能会划出商品子域、物流子域。如何为每个子域划分出多个实体、聚合、服务,如何每一个实体和聚合设计它们的事件,如何为每一个实体设计它们的仓库。这就是DDD要做的事情!
贫血和充血?
贫血的代码是指数据和行为的分离,业务系统迭代中行为多变和数据的多变会导致代码的难以维护。来看一个贫血读取商品的演进
package service///获取商品func GetGoods(goodsId int) dao.Goods { return orm.GetGoods(goodsId)}
PM 一个月后增加了自动选择优惠券功能
//增加了优惠券package service//获取商品func GetGoods(goodsId int) dao.Goods { return orm.GetGoods(goodsId)}// 获取有优惠券的商品func GetGoodsByCoupon(goodsId int) dao.Goods { goods := GetGoods(goodsId) coupon := orm.GetCoupon() //优惠券和商品逻辑略过.... return}
PM 2个月后加入了限时折扣,不可以叠加优惠券,自动选择最优。
这个限时折扣该加哪,虽然各种if else也能加,那么以后pm在加逻辑呢?这里就不浪费笔墨了。
充血的代码
func GetGoods(goodsId int) entity.Goods { //获取优惠券实体 coupon := repository.GetCoupon() //获取商品实体 goods := repository.GetGoods(goodsId)
//如果优惠券减免大于限时折扣 if coupon.SubPrice(goods) > goods.TimeLimitPrice() { //使用优惠券 goods.UseCoupon(coupon) return goods } return goods}
//实体不应该仅仅只有数据,而且必须要有行为func (c *coupon) SubPrice(goods entity.Goods) int {}
func (c *goods) TimeLimitPrice() int {}func (c *goods) UseCoupon(coupon entity.Coupon){}
战略和战术?
战略建模主要划分子域和使用限界上下文,通常用于划分微服务和设计服务与服务之间的关联。子域分为核心域、支撑子域、通用子域。以一个金融公司领域来看,股票服务是这个公司的核心域,账户服务是这个公司的支持子域。更多参考<<实现领域驱动设计>>,本教程以go
语言来做战术设计的落地。战术设计主要涉及下文目录相关的知识点。
目录
- golang领域模型-开篇
- golang领域模型-六边形架构
- golang领域模型-实体
- golang领域模型-资源库
- golang领域模型-依赖倒置
- golang领域模型-聚合根
- golang领域模型-CQRS
- golang领域模型-领域事件
项目代码 https://github.com/8treenet/freedom/tree/master/example/fshop
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 【技术创作101训练营】想用代码改变世界?先用好Git和Github!
- 绘制散点图(克利夫兰系列)
- 绘制分组散点图(克里夫兰点图)
- ggplot2绘制玫瑰图
- 绘制极坐标系条形图
- 四步重新认识冗余机器人的控制器设计
- 人脸识别接入常见问题汇总
- TKE上关于postStart 和preStop使用
- 文字识别接入常见问题
- 从 1 到 0 构建博客项目(2) -- 操作系统篇(2)--定制Centos
- 使用Angular依赖注入自定义SAP Spartacus的ProductAdapter
- 获取SAP Spartacus当前显示产品json数据的又一办法
- SAP Spartacus注入自定义的CurrentProductService
- Redis系列(十三)应用之分布式锁
- Oracle数据库 sql条件查询语句与练习