领域驱动设计,让程序员心中有码(五)

1      从搬砖谈领域对象

  有一个古老的故事,大概是这样的。作者问三个建筑工地上的工人他们在干什么?有一个没精打采的说,我在挖洞!而另一一个人却说,我在盖一座房子。还有一个人说,我在建立一座巨大的城市。不同的思维模式决定了不同的发展,十年过后,第一个工人,还是在挖洞,而第二个则成为了工头。第三个最终却成为了大设计师。

  在软件开发领域,往往会使用搬砖这个词来形容我们所开发的每个功能模块,实际上也确实如此,如果把我们需要完成的每个项目,比作一座高楼大厦,那么在项目中所完成的各种模块,也确实是我们在计算机世界中利用砖块设计出来的精美建筑构建。而从领域驱动的角度来说,可以把关系,类比为建筑工程图纸中使用的各种辅助线,也可以把领域驱动中所涉及的各个对象,类比成砖块,这些砖块,大概有两种:一种是实体(Entity),一种是值对象(Value Object),而使用这些对象的工具,则成为服务(Service),完成的各个建筑构建,被成为包或者模块(Module).

2      关联关系

  在介绍领域驱动设计的第三篇文章中,作者提到了UML中常用的几种关系,而关联关系是一种最为常见的关系。在软件设计过程中,无所不在的关联,有时候会让软件工程设计变得更加复杂。因此,在设计关联关系时,应该让关联更加易于控制,这意味着需要采取下列三种措施:

  1、规定一个遍历方向。对象与对象间,过于双向关联是一种低效的关系,而指定唯一的遍历方向,将有效的减少相互的依赖,实现设计的简化。

  2、添加一个限定符,以便有效地减少多重关联。过于复杂的多对多关系,最终形成一个纷繁复杂难以控制的图结构,而限定多对多关联的遍历方向,可以有效的简化多对多关系为一对多关联。

  3、消除不必要的关联。上述两个步骤的目的,也正是为了消除对于当前工作或模型对象的基本含义来说不重要的关联。实际上正是为了当前模型对象的简化。

3      实体

  在软件开发过程中,我们通常会定义模型和实体对象,这种实体对象同样也是领域驱动中的基本对象。按照大家的理解,通常而言,实体是指能够与数据库直接映射的对象。在领域驱动设计中,使用的则是更加妥当的说法:对象具有贯穿整个生命周期(甚至会经历多种形式)的抽象的连续性。 实体标识任何事物,只要满足两个条件即可:一个是它在整个生命周期中,具有联系性,二是他的区别并不是有哪些对用户来说非常重要的属性决定,而是通过标识来决定的。

    3.1   实体建模

  由于实体对象的基本职责是为了确保连续性,其行为应该是非常清楚并且可以预测的。因此保持实体的简练是实现责任的关键。应该抓住实体的基本特征,而不要一味地过分求全求完美。对于实体而言,应该只添加对概念来说至关重要的行为和这些行为所必须的属性。其他行为,应当转移到与核心实体关联的其他对象中。实体则通过协调与之关联的其他对象来完成自己的基本职责。

3.2   设计实体的标识

  在面向对象开发中,会使用建立标识这种操作方式来实现与其他对象的区分。哪怕是在分布式系统中,同样需要使用标识来确保标识的唯一性。可以使用具有唯一性的属性来提供标识,也可以使用ID的方式来实现。这种ID如果使用系统自动生成,往往需要有一些手段确保生成的唯一性,尤其是在分布式系统中,更是一个非常困难的问题。经常使用的方式是使用redis或zookeeper这些中间件来生成唯一标识,还有一种常见的方案是使用twitter的Snowflake算法,这些算法就不再赘述了。

4      值对象

  值对象则不具备Entity这种明确的连续性,如果在设计系统时,将所有的对象都定义为实体对象,实际上将会极大的增加系统的复杂度,所以需要定义一些用于描述领域的某个方面,本身没有概念标识的喜爱那个。例如,可以通过邮编对地址进行检索,邮编的变更,对地址也可能会发生变化,那么地址就是具有连续性的实体对象。而在电子商务系统中,只需根据地址即可完成投递,而无需确保地址的连续性,那么他就是值对象了。

  值对象,往往使用与需要通过一个模型元素的属性来定义模型的场景,主要作为参数在对象间传递消息。通常是临时对象,在操作结束后,就可以被丢弃。值对象可以作为实体的属性,例如,一个人,是一个完整的实体,而他的名字,则是值对象。当然,也并非意味着值对象是一个单纯的属性,实际上值对象是指某一个特定概念下,具有完整意义的、通过属性进行理解的对象。例如,地址由省、市、区、街道、邮编等综合属性组成,这些组成对象,实际上也是实体,他们联系起来,就组成了值对象。

5      服务

  在软件设计中,并非所有的对象都需要通过标识或属性进行区分。领域驱动设计中,使用服务(Service)来定义具有活动或动作的对象。事实上也确实如此,并非所有的对象都适合使用实体或值对象来进行建模。服务强调与其他对象的操作,是通过定义能够为使用者做什么来实现的。也就是说,服务倾向于动词领域,而非名词领域。

  5.1   服务对象的基本特征

  按照领域驱动设计的说法,一个好的服务应该具有以下特征:

  1)与领域概念相关的操作,不是Entity或ValueObject的一个自然组成部分。

  2)接口是根据领域模型的其他元素定义。

  3)操作是无状态的。操作的无状态是指任何调用者都能使用,而无需关注实例的历史状态。

5.2   服务与领域层

  在领域涉及中,服务无处不在,大体上包括以下几种不同层次。

  1、应用层:定义与应用相关的基础服务,例如在处理资金转账业务时,定义一系列服务,1、包括获取输入,2、发送消息给领域层服务,由其完成动作的执行;3、监听确认消息等。

  2、领域层:处理与相关的服务,例如,处理有上述转账业务发起的请求,例如进行结果的确认等。

  3、基础设施层:发送消息通知。

  5.3   服务的粒度

在概念建模中,通过控制领域层中接口的力度,可以有效的实现客户端与实体和值对象的耦合。通过合理的模式确保接口的简单性,将便于在大型或分布式系统中对组件进行打包的粒度控制,这实际上也是微服务架构中,服务粒度细分的理论基础。

6      包或模块

  模块,是软件工程学中自古有之的基本概念。在软件系统设计中,经常会按照各种各样的类别进行分解,有时候按照技术架构来分割,有时候则按照开发者的任务例如按照用例来进行细分,有的在软件重构过程中,甚至会沿用历史架构早期形成的模块划分。

  在软件工程学中,高内聚,低耦合是基本的概念,而在模块之间的关系,成为耦合,而模块内部的关系,成为内聚。因此,好的软件项目,模块之间应该低耦合,而模块内部则应该高内聚。但是模块的划分,跟软件分层划分一样,不应该仅仅只是代码层面的划分,而应该是概念模型角度的划分。不连贯的思想或者“一锅粥”式的模块划分,最终只会造成系统开发的严重不可控。

  领域驱动设计认为,模块,是一种非常重要的表达机制。模块的选择应该取决于被花费到模块中的对象的意义。当某些对象在模块中被创建时,实际上相当于告诉下一位开发者,这些对象间是通过模块来实现了某种关系。

  选择能够描述系统的模块,并使之饱含一个内聚的概念集合。应该基于模块来实现概念组合的方式,从而可以向相互独立地理解和分析这些概念。对模型进行精化,直到可以更具高层领域概念对模型进行划分,同时,相应的代码也不会产生耦合。

7      结论

  随着系统设计规模和复杂度的增加,模块化变得更加重要。领域模型中的每个概念都需要在实现元素中反映出来。实体、值对象、他们之间的关联关系、领域服务以及用于组织元素的模块都是实现领域模型相对应的地方。实现中的对象、指针和检索机制必须直接、清楚地映射到模型对象。

原文地址:https://www.cnblogs.com/xiyuanMore/p/10230801.html

时间: 2024-08-29 18:48:03

领域驱动设计,让程序员心中有码(五)的相关文章

领域驱动设计-让程序员心中有码(九)

一.易于腐化的软件设计 犹记得刚刚参加工作时,是地图厂商四维图新集团旗下的一家子公司,主要从事规划测绘相关软件研发的公司.当时我的项目是为勘测设计院提供相对应的应用软件,对地理信息和规划相关的图纸信息,几乎已经专业水平.事实上,规划设计大概和软件设计类似,有规划的设计.或无规划的设计,造成的结果几乎是天壤之别. 我们或许很容易就能设想到一个毫无规划设计的城市,纵横交错的路网.杂乱无章式的建筑布局.各种凌乱的棚户区设计,恰好象征着软件设计的无序性,也恰好体现了软件企业在经费不足.组织缺乏管理.开发

领域驱动设计,让程序员心中有码(七)

领域驱动设计- 让程序员心中有码(七) -设计原则和设计模式,互联网开发者们共同的追求 前言 多年来,笔者一直从事传统软件企业的软件开发和项目管理工作.笔者发现在众多的传统软件企业中,评判优秀开发者的标准往往是技能的熟练程度,基本上都是以梭代码的速度论英雄.有人评价说,这种开发可以称之为cv编程,即ctrl+c和ctrl+v编程为主.这种开发往往对开发者的技能要求并没有想象中的那么高,由于工时和合同的限制,不得不压缩开发时间,通过靠密集的劳动力资源.较高的工作强度来完成项目的开发.这种模式,通过

领域驱动设计,让程序员心中有码(二)

  引子,软件工程没有银弹    上一篇博文,抛出了一个问题,领域驱动设计真的是万能的良方吗?对于这个问题,大家的答案无疑是一致的,作为一种非常受软件行业欢迎的软件思想,领域驱动设计固然有很多优点,却并非万能.  回到十年前,第一节软件工程学的课堂上,我们的老师就告诉了我们一句真理,软件工程没有银蛋,这句话说的是,软件工程领域,从来没有一种思想或理论能够带来成倍的效率提升.不知不觉,十年过去,我们大概可以看到,软件开发新技术日新月异,新语言层出不穷,但是无论哪种技术,都不见得相对于其所对标的技术

领域驱动设计系列(转)

曾经参与过系统维护或是在现有系统中进行迭代开发的软件工程师们,你们是否有过这样的痛苦经历:当需要修改一个Bug的时候,面对一个类中成百上千行的代码,没有注释,千奇百怪的方法和变量名字,层层嵌套的方法调用,混乱不堪的结构,不要说准确找到Bug所在的位置,就是要清晰知道一段代码究竟是做了什么也非常困难.最终,改对了一个Bug,却多冒出N个新Bug.同样的情况,当你拿到一份新的需求,需要在现有系统中添加功能的时候,面对一行行完全过程式的代码,需要使用一个功能时,不知道是应该自己编写,还是应该寻找是否已

领域驱动设计系列(3)有选择性的使用领域驱动设计

本系列的第一篇博文抛砖引玉,大谈领域驱动设计的优势,这里笔者还是希望以客观的态度,谈谈领域驱动设计的缺点及其不适合使用的场景,以让读者可以有选择性的使用领域驱动设计. 我们知道,没有最好,只有最合适,设计也是一样.因此,所谓设计,就是以你和你的团队的知识.经验和智慧,全面充分的考虑各种内外因素后,在你们的设计方案中作出合理的选择的过程.而这些影响你们选择的因素主要有: 技术框架的特征和约束(如果你的项目决定使用C语言进行开发,那么首先在设计方法上,就需要使用面向过程而非面向对象的设计方法). 时

领域驱动设计系列文章(3)——有选择性的使用领域驱动设计

本系列的第一篇博文抛砖引玉,大谈领域驱动设计的优势,这里笔者还是希望以客观的态度,谈谈领域驱动设计的缺点及其不适合使用的场景,以让读者可以有选择性的使用领域驱动设计. 我们知道,没有最好,只有最合适,设计也是一样.因此,所谓设计,就是以你和你的团队的知识.经验和智慧,全面充分的考虑各种内外因素后,在你们的设计方案中作出合理的选择的过程.而这些影响你们选择的因素主要有: 技术框架的特征和约束(如果你的项目决定使用C语言进行开发,那么首先在设计方法上,就需要使用面向过程而非面向对象的设计方法). 时

DDD领域驱动设计基本理论知识总结

领域驱动设计之领域模型 加一个导航,关于如何设计聚合的详细思考,见这篇文章. 2004年Eric Evans 发表Domain-Driven Design –Tackling Complexity in the Heart of Software (领域驱动设计),简称Evans DDD.领域驱动设计分为两个阶段: 以一种领域专家.设计人员.开发人员都能理解的通用语言作为相互交流的工具,在交流的过程中发现领域概念,然后将这些概念设计成一个领域模型:由领域模型驱动软件设计,用代码来实现该领域模型:

从三层架构迈向领域驱动设计

本文读者基本要求:从事信息管理系统开发,略懂GOF设计模式及SOLID设计原则,对三层面向过程机械编码厌倦,并且不知道出路在何方,如果还掌握代码坏味和重构手法,那是极好的. 1. 三层架构 理论介绍-->实际经验-->总结反思 1.1 简单介绍三层架构 严格分层架构模式的特点是上层只能访问相邻的下层,其他层次间的调用都不允许.三层架构就是一种严格分层模式,它把职责划分为界面展示.业务逻辑.数据访问三层,还有一个业务实体,前面三层都要依赖它,所以它并不构成一个层.结构如图1. 三层架构的特点是一

[转]DDD领域驱动设计基本理论知识总结

领域驱动设计之领域模型 加一个导航,关于如何设计聚合的详细思考,见这篇文章. 2004年Eric Evans 发表Domain-Driven Design –Tackling Complexity in the Heart of Software (领域驱动设计),简称Evans DDD.领域驱动设计分为两个阶段: 以一种领域专家.设计人员.开发人员都能理解的通用语言作为相互交流的工具,在交流的过程中发现领域概念,然后将这些概念设计成一个领域模型:由领域模型驱动软件设计,用代码来实现该领域模型: