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

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      服务

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zwjpdp.html