0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

如何实现DCI架构(上)

jf_78858299 来源:元闰子的邀请 作者:元闰子 2023-05-10 17:09 次阅读

前言

在面向对象编程的理念里,应用程序是对现实世界的抽象,我们经常会将现实中的事物建模为编程语言中的类/对象(“ 是什么 ”),而事物的行为则建模为方法(“ 做什么 ”)。面向对象编程有 三大基本特性 (封装、继承/组合、多态)和 五大基本原则 (单一职责原则、开放封闭原则、里氏替换原则、依赖倒置原则、接口分离原则),但知道这些还并不足以让我们设计出好的程序,于是很多方法论就涌现了出来。

近来最火的当属领域驱动设计(DDD),其中战术建模提出的实体、值对象、聚合等建模方法,能够很好的指导我们设计出符合现实世界的领域模型。但DDD也不是万能的,在某些应用场景下,按照传统的战术建模/面向对象方法设计出来的程序,也会存在可维护性差、违反单一职责原则等问题。

本文介绍的DCI建模方法可以看成是战术建模的一种辅助,在某些场景下,它可以很好的弥补DDD战术建模的一些缺点。接下来,我们将会通过一个案例来介绍DCI是如何解决DDD战术建模的这些缺点的。

本文涉及的代码归档在github项目:https://github.com/ruanrunxue/DCI-Architecture-Implementation

案例

考虑一个普通人的生活日常,他会在学校上课,也会趁着暑假去公司工作,在工作之余去公园游玩,也会像普通人一样在家吃喝玩乐。当然,一个人的生活还远不止这些,为了讲解方便,本文只针对这几个典型的场景进行建模示例。

图片

使用DDD建模

按照DDD战术建模的思路,首先,我们会列出该案例的 通用语言

人、身份证、银行卡、家、吃饭、睡觉、玩游戏、学校、学生卡、学习、考试、公司、工卡、上班、下班、公园、购票、游玩

接着,我们使用战术建模技术( 值对象实体聚合领域服务资源库 )对通用语言进行领域建模。

DDD建模后的代码目录结构如下:

- aggregate: 聚合
  - company.go
  - home.go
  - park.go
  - school.go
- entity: 实体
  - people.go
- vo: 值对象
  - account.go
  - identity_card.go
  - student_card.go
  - work_card.go

我们将身份证、学生卡、工卡、银行卡这几个概念,建模为 值对象 (Value Object):

package vo

// 身份证
type IdentityCard struct {
 Id   uint32
 Name string
}

// 学生卡
type StudentCard struct {
 Id     uint32
 Name   string
 School string
}

// 工卡
type WorkCard struct {
 Id      uint32
 Name    string
 Company string
}

// 银行卡
type Account struct {
 Id      uint32
 Balance int
}

...

接着我们将人建模成 实体 (Entity),他包含了身份证、学生卡等值对象,也具备吃饭、睡觉等行为:

package entity

// 人
type People struct {
 vo.IdentityCard
 vo.StudentCard
 vo.WorkCard
 vo.Account
}

// 学习
func (p *People) Study() {
 fmt.Printf("Student %+v studying\\n", p.StudentCard)
}
// 考试
func (p *People) Exam() {
 fmt.Printf("Student %+v examing\\n", p.StudentCard)
}
// 吃饭
func (p *People) Eat() {
 fmt.Printf("%+v eating\\n", p.IdentityCard)
 p.Account.Balance--
}
// 睡觉
func (p *People) Sleep() {
 fmt.Printf("%+v sleeping\\n", p.IdentityCard)
}
// 玩游戏
func (p *People) PlayGame() {
 fmt.Printf("%+v playing game\\n", p.IdentityCard)
}
// 上班
func (p *People) Work() {
 fmt.Printf("%+v working\\n", p.WorkCard)
 p.Account.Balance++
}
// 下班
func (p *People) OffWork() {
 fmt.Printf("%+v getting off work\\n", p.WorkCard)
}
// 购票
func (p *People) BuyTicket() {
 fmt.Printf("%+v buying a ticket\\n", p.IdentityCard)
 p.Account.Balance--
}
// 游玩
func (p *People) Enjoy() {
 fmt.Printf("%+v enjoying park scenery\\n", p.IdentityCard)
}

最后,我们将学校、公司、公园、家建模成 聚合 (Aggregate),聚合由一个或多个实体、值对象组合而成,组织它们完成具体的业务逻辑:

package aggregate

// 家
type Home struct {
 me *entity.People
}
func (h *Home) ComeBack(p *entity.People) {
 fmt.Printf("%+v come back home\\n", p.IdentityCard)
 h.me = p
}
// 执行Home的业务逻辑
func (h *Home) Run() {
 h.me.Eat()
 h.me.PlayGame()
 h.me.Sleep()
}

// 学校
type School struct {
 Name     string
 students []*entity.People
}
func (s *School) Receive(student *entity.People) {
 student.StudentCard = vo.StudentCard{
  Id:     rand.Uint32(),
  Name:   student.IdentityCard.Name,
  School: s.Name,
 }
 s.students = append(s.students, student)
 fmt.Printf("%s Receive stduent %+v\\n", s.Name, student.StudentCard)
}
// 执行School的业务逻辑
func (s *School) Run() {
 fmt.Printf("%s start class\\n", s.Name)
 for _, student := range s.students {
  student.Study()
 }
 fmt.Println("students start to eating")
 for _, student := range s.students {
  student.Eat()
 }
 fmt.Println("students start to exam")
 for _, student := range s.students {
  student.Exam()
 }
 fmt.Printf("%s finish class\\n", s.Name)
}

// 公司
type Company struct {
 Name    string
 workers []*entity.People
}
func (c *Company) Employ(worker *entity.People) {
 worker.WorkCard = vo.WorkCard{
  Id:      rand.Uint32(),
  Name:    worker.IdentityCard.Name,
  Company: c.Name,
 }
 c.workers = append(c.workers, worker)
 fmt.Printf("%s Employ worker %s\\n", c.Name, worker.WorkCard.Name)
}
// 执行Company的业务逻辑
func (c *Company) Run() {
 fmt.Printf("%s start work\\n", c.Name)
 for _, worker := range c.workers {
  worker.Work()
 }
 fmt.Println("worker start to eating")
 for _, worker := range c.workers {
  worker.Eat()
 }
 fmt.Println("worker get off work")
 for _, worker := range c.workers {
  worker.OffWork()
 }
 fmt.Printf("%s finish work\\n", c.Name)
}

// 公园
type Park struct {
 Name     string
 enjoyers []*entity.People
}
func (p *Park) Welcome(enjoyer *entity.People) {
 fmt.Printf("%+v come to park %s\\n", enjoyer.IdentityCard, p.Name)
 p.enjoyers = append(p.enjoyers, enjoyer)
}
// 执行Park的业务逻辑
func (p *Park) Run() {
 fmt.Printf("%s start to sell tickets\\n", p.Name)
 for _, enjoyer := range p.enjoyers {
  enjoyer.BuyTicket()
 }
 fmt.Printf("%s start a show\\n", p.Name)
 for _, enjoyer := range p.enjoyers {
  enjoyer.Enjoy()
 }
 fmt.Printf("show finish\\n")
}

那么,根据上述方法建模出来的模型是这样的:

图片

模型的运行方法如下:

paul := entity.NewPeople("Paul")
mit := aggregate.NewSchool("MIT")
google := aggregate.NewCompany("Google")
home := aggregate.NewHome()
summerPalace := aggregate.NewPark("Summer Palace")
// 上学
mit.Receive(paul)
mit.Run()
// 回家
home.ComeBack(paul)
home.Run()
// 工作
google.Employ(paul)
google.Run()
// 公园游玩
summerPalace.Welcome(paul)
summerPalace.Run()

贫血模型 VS 充血模型(工程派 VS 学院派)

上一节中,我们使用DDD的战术建模完成了该案例领域模型。模型的核心是People实体,它有IdentityCardStudentCard等数据属性,也有Eat()Study()Work()等业务行为 ,非常符合现实世界中定义。这也是学院派所倡导的,同时拥有数据属性和业务行为的 充血模型

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 应用程序
    +关注

    关注

    37

    文章

    3244

    浏览量

    57610
  • DCI
    DCI
    +关注

    关注

    0

    文章

    39

    浏览量

    6807
  • 面向对象编程

    关注

    0

    文章

    22

    浏览量

    1807
收藏 人收藏

    评论

    相关推荐

    DCI 颠覆光器件产业?

    DCI的理念使产品设计思维陷入两难境地。DCI引导行业深入研究了COB生产工艺,现在人们确实在COB工艺取得巨大推进。对于新技术的光模块、DCI正成为首批商用的试验场所。我们相信
    发表于 02-08 15:53

    Xilinx FPGA DCI使用方法

    各位大神,请问Xilinx FPGA中的DCI是如何使用的?我知道是把每个Bank的VRP、VRN管脚分别下拉、拉,除此之外,在HDL代码和约束中应该如何写呢?查了半天资料没有查到,所以来论坛问问。@LQVSHQ
    发表于 08-20 20:51

    为什么银行也没有DCI匹配?

    在ml_605的示意图中,我发现在一个银行(例如银行16)中混合了LVDS信号和信号端信号,所以银行应该收起2.5v,并且银行有DCI匹配。但是在银行24(银行混合了LVDS信号和信号端信号),所以
    发表于 10-25 08:47

    如何在IBIS文件中配置SSTL135 DCI阻抗

    嗨,我正在尝试使用Hyperlynx来模拟K7的DDR3L设计。我使用Vivado write_ibis根据我的FPGA设计生成ibis文件。对于SSTL135_DCI_HP_IN50_I信号,我
    发表于 07-14 09:10

    使用KC705板晶振作为参考时钟生成DCI和data,有很多跳动的杂波信号是怎么回事?

    最近配置AD9139的时候,分别采用了两种方式。一种是直接使用KC705板晶振作为参考时钟生成DCI和data,DAC单独供参考时钟,另一种是使用AD9139评估板分频得到的DCO作为FPGA
    发表于 12-04 06:53

    MIPS联手SySDSoft在MIPS 架构实现LTE技术

    MIPS联手SySDSoft在MIPS 架构实现LTE技术 美普思科技公司(MIPS )和4G移动WiMAX、LTE嵌入式软件方案领先供货商SySDSoft公司宣布,双方将合作实现
    发表于 03-01 11:28 552次阅读

    MIPS和SySDSoft合作在MIPS架构实现LTE技术

    MIPS和SySDSoft合作在MIPS架构实现LTE技术  美普思科技公司和4G移动WiMAX、LTE嵌入式软件方案领先供货商SySDSoft公司宣布,双方将合作实现MIPS
    发表于 03-02 10:17 571次阅读

    MIPS科技和SySDSoft共同在MIPSTM 架构实现

    MIPS科技和SySDSoft共同在MIPSTM 架构实现LTE技术 美普思科技公司(MIPS Technologies)和SySDSoft公司宣布,双方将合作实现MIPSTM
    发表于 03-03 10:00 848次阅读

    DCI是什么?Xilinx 7系列FPGA的HP bank都支持DCI

    DCI的缩写,应该也算上xilinx 在IO feature的一项技术(这不是7系列才有的新技术)。DCI从字面上看含义是可控制的阻抗,启动DCI功能可以减少单板为阻抗匹配所需要的
    发表于 06-27 09:11 1.9w次阅读
    <b class='flag-5'>DCI</b>是什么?Xilinx 7系列FPGA的HP bank都支持<b class='flag-5'>DCI</b>

    什么是DCI-BOX?为什么会出现这个东西?

    但为什么会出现这个东西?在我看来,主要是场景和成本两方面决定。场景DCI-BOX说高大一点是面向新一代城域网的架构,如城域分发(POD),云网入网点(POP)等功能区的应用场景。
    的头像 发表于 11-18 09:35 1.2w次阅读

    DCI BOX与传统WDM/OTN设备有什么区别?

    DCI-BOX,中国联通叫模块化波分设备,中国电信叫盒式波分设备DCI-BOX,是数据中心点到点互连(DCI)的设备。在DCI BOX出现之前,DC
    的头像 发表于 03-26 14:29 1730次阅读

    易飞扬非相干DCI BOX的DCI传输方案介绍

    易飞扬推出的最新1U 800G DWDM DCI BOX是一款1U盒式的多业务波分传输平台,可满足最大8×100GE业务点对点传输的应用场景,单机框常规接入容量800G。它同样满足DCI对小体积、低功耗、极简维护、低时延、大带宽的需求。
    发表于 04-21 10:39 526次阅读

    非相干DCI BOX,提供更经济的DCI传输方案

    易飞扬推出的最新1U 800G DWDM DCI BOX是一款1U盒式的多业务波分传输平台,可满足最大8×100GE业务点对点传输的应用场景,单机框常规接入容量800G。它同样满足DCI对小体积、低功耗、极简维护、低时延、大带宽的需求。
    的头像 发表于 04-21 10:40 852次阅读

    非相干DCI BOX,提供更经济的DCI传输方案

    上文,我们介绍了相干DCI BOX完美适配目前DCI传输的应用,不过,相干子系统的成本向来比较高,那是否有成本较低的非相干设备可供选择?考虑到不同用户的预算需求,易飞扬同样提供经济型的非相干DCI BOX,本文介绍的1U 800
    的头像 发表于 04-24 09:46 855次阅读
    非相干<b class='flag-5'>DCI</b> BOX,提供更经济的<b class='flag-5'>DCI</b>传输方案

    如何实现DCI架构(中)

    在面向对象编程的理念里,应用程序是对现实世界的抽象,我们经常会将现实中的事物建模为编程语言中的类/对象(“ **是什么** ”),而事物的行为则建模为方法(“ **做什么** ”)。面向对象编程有 **三大基本特性** (封装、继承/组合、多态)和 **五大基本原则** (单一职责原则、开放封闭原则、里氏替换原则、依赖倒置原则、接口分离原则),但知道这些还并不足以让我们设计出好的程序,于是很多方法论就涌现了出来。
    的头像 发表于 05-10 17:10 658次阅读
    如何<b class='flag-5'>实现</b><b class='flag-5'>DCI</b><b class='flag-5'>架构</b>(中)