关于领域驱动设计与开发过程中的一些疑惑请道友帮忙解惑,谢谢。

smcdl 16-06-06
    

大家好,对于领域驱动设计开发来说我是一个新人,目前我在项目中强制自己实施领域驱动设计开发,为的是让自己能快速理解领域驱动设计并在开发中运用自如,但实际结果是处处都是问题,手里有两本书,但看了之后感觉问题更多,下面我问几个我目前最关心的问题,希望在此路上已有成就的道友能帮我一把。

1.领域驱动设计里的所说的Repository的概念是我们以前用的DAO概念吗?目前我在使用Spring的JPA来进行开发,里面有一个JPARepository的概念, 但我的理解JPARepository的概念就是以前所熟悉的DAO模式,但是就是不知道是否是领域驱动设计里所说的Repository的概念了。

2.聚合对象(或者聚合根对象,我也不知道这两个是不是一个东西)大概是一个什么样的对象,书里基本上都是讲概念而没什么例子,如果一个对象里有另一个对象的集合,而对另一个对象集合中添加删改都通过当前对象来操作,那么当前对象就是聚合根吗?

3.Model与Entity可以是一个东西吗?Model一般指的是领域模型对象,Entity一般指数据库中的实体对象,但就我以前的开发经验来看Entity肯定是贫血模型,而领域驱动中设计的Model对象肯定一本都不是贫血模型,另外书中有说Model是通过Repository取得,如果Model和Entity是一回事,那么Repository岂不是和DAO是一回事了吗?之所以提出这个问题在于,我现在应用的模型是Model为充血模型,而Model是从JPARepository中取得的,但JPARepository在基础架构层,而Model在领域层,这样层间的引用关系岂不是反过来了吗?虽然书上有说依赖倒置原则,但那是对接口而言,对于我这种情况肯定不是依赖倒置的问题啊。

4.在一本书里看到对于Repository的描述,其中一种是类似Hibernate那种,对于Hibernate我没用过太多,对它的理解也不是很透彻,但通过书中的描述我理解是通过Repository取出的Model后,其Model对象本身就能直接操作数据库,也就是对对象的任何修改都能直接更新数据库,不需要显示的再次调用Repository的save方法,与之对应的另一种模式就是显示调用Repository的save方法才能将Model的改动持久化到数据库中,那么无论采用那种模式,从这段描述中我觉得领域驱动中的Repository越来越像DAO了,如果我的理解不对,请道友指正。

5.最后一个问题是与我目前的项目相关的,根据六边形法则,接口层应该放置不同类型用户访问的接口,我的项目有两个接口,一个HTTP接口,提供Restful API给移动设备使用,另一个是Socket接口,提供字符流给一些单片机设备使用。Socket接口使用Netty组件来实现,Netty组件里已经封装了很多Socket的东西,但业务相关的东西还是需要自己来实现,但哪些是我需要放在基础架构层的,哪些是需要放在接口层的呢?我以前的做法是将关于Socket接口的全部代码都放在基础架构层,但看了六边形法则后我觉得Socket也是一种接口,只不过面向的不是移动设备而是单片机设备而已,那么问题是将哪一部分拿到接口层呢,目前我是将自己的业务实现写在继承ChannelDuplexHandler的类中,那么我感觉应该把关于业务实现的类拿到接口层中,不知道我想的对不对,请道友帮忙解惑。

以上是我在应用领域驱动设计与开发过程中遇到的问题,希望道友不吝赐教,谢谢。

    

1
banq
2016-06-06 12:39

DAO是数据访问对象(Data Access Object),而Repository是对象仓储,实际是数据库数据Data和内存对象Object不同侧重点的称谓,这种侧重点不同实际是鸡生蛋还是蛋生鸡的问题。

DAO是侧重数据库数据Data,内存中对象是为数据库数据服务的,这个对象根据数据表数据可以任意合成任意对象,有时一个数据表会合成很多DAO对象,尽管这些DAO对象之间可能就相差几个字段。因此, DAO是先有数据表Schema结构设计以后,再有Java等语言的类或对象。

而Repository正好相反,是侧重内存中对象,这个仓储是用来储备什么的呢?储备对象的,储备哪儿去?储备到数据库中,数据库类似仓储中的一个存储地点,可以有很多其他存储地点。那么被储备的对象是从哪儿来的呢?是从需求业务分析而来的。这个对象成为领域模型对象,因此,这个对象不像DAO那样是随意任意构建的,而是代表业务模型,数据库表结构也必须服从业务模型。

所以,是先有业务模型还是先有数据表结构,决定DAO和Respository侧重点不同。如同先有鸡或先有蛋,那么世界观就会不同一样。

具体实现时DAO和Repository的不同可以参考:http://www.jdon.com/48016,名词虽然不同,但是都是在谈论这块。

如果你确定先有业务模型,那么聚合对象就容易理解,聚合对象是一群业务模型,比汽车是一个聚合对象,其有车轮 发动机 车身等众多子对象组成。

如果你确定先有业务模型,那么就知道Model和Entity是否是一个东西,Model是业务模型,而Entity是数据库中实体数据在内存中的对象。Model是一个代表业务模型对象,真正对象是应该有行为的,而Entity只是数据表数据的影子,当然不需要行为,是贫血模型,这些可查看以前帖子讨论。

关于socket将业务层和基础层分离思路是对的,接口层需要想象成是一个interface,如同Java的接口代码,很少很薄,只是个面子,因此接口层不能放入太多代码。总之这些都根据一些基本设计原则去考虑。





smcdl
2016-06-06 13:45

感谢板桥您的答复,但我还有不明白的地方,请您帮我解惑。

那么对于Model与Entity、Repository与DAO,我是不是可以这样理解,DAO是针对数据库表进行操作,他操纵的对象是Entity,而Repository是针对领域模型对象的操作,他操纵的对象是Model,如果从数据库中取出一个领域对象,需要通过Repository来操纵DAO来从数据库取出Entity对象,然后再通过相应的Factory等设施构造Model对象并用Entity对象的值来填充Model对象,目的是封装与领域无关的底层数据存储功能,让调用Repository的上层无需关心领域对象的是如何持久化的。

另外问一下Spring里的JPARepository是不是就是DAO模式,虽然它带有Repository的字样。

对于聚合的例子,我一直没有直观的概念,一个Model对象可以是一个聚合根吗?还是说聚合根是一个独特的对象,从聚合根里面取出Model对象。就像UML中的Stereotype那样,聚合根对象是否需要继承什么类或者实现什么接口声明自己是聚合类型,还是仅仅暴露一些方法针对包含的部件集合进行增删改就可以了呢?
[该贴被smcdl于2016-06-06 13:52修改过]

banq
2016-06-06 14:04

2016-06-06 13:45 "@smcdl"的内容
那么对于Model与Entity、Repository与DAO ...

不是你说的意思,你说的已经进入操作层面。

假设我们要做一个论坛系统,怎么做?首先做什么?有两种:
A.如果首先设计数据表结构,比如Forum和Post两个表。
B.如果DDD,那么设计Forum和Post两个领域模型Model对象,可以用UML类图表达,然后写出Java或其他类的代码。

如果先从A开始做,那么无疑使用Entity表达Forum和Post,有两个实体对象,对应两张表。至于DAO就是用来进行对象和表之间转换的持久层。

如果先从B开始做,那么使用Repository将Forum和Post两个领域对象进行持久,这时需要确定持久到哪里,如果持久到数据表,再设计数据表结构,或者使用Hibernate自动生成数据表。

所以,先有鸡和先有蛋决定了后面前后顺序不一样。理解上面区别,你对聚合就会了解,因为我们直接使用模型对象反映需求,那么Car这个对象反映了业务世界汽车,而汽车是由车轮 方向盘 马达等组成,对应我们的Car模型对象由Wheel、Engine 等对象组成。类的代码如下:


public class Car{
private Wheel wheel;
private Engine engine;

..
}

上面代码就表示汽车由方向盘和马达组成,我们就直接用类表达了业务需求,这时不会掺入任何数据表的事情。这时的汽车由于聚合了几个子对象,称为聚合根,如同小组长一样。

而如果首先从数据表开始做系统,则会设计出数据表结构:

CREATE TABLE car(
carID BIGINT NOT NULL,
name VARCHAR(100) NOT NULL,
PRIMARY KEY (carID)
);

CREATE TABLE wheel(
wheelID BIGINT NOT NULL,
name VARCHAR(100) NOT NULL,
PRIMARY KEY (wheelID)
);

CREATE TABLE engine(
engineID BIGINT NOT NULL,
name VARCHAR(100) NOT NULL,
PRIMARY KEY (engineD)
);


上面是设计好MySQL数据表,最多在wheel和engine中设计一个外键指向carID,这就是用表关联表达汽车和方向盘与马达的关系。当然这种表达有很多缺点,不能表达很紧密的关系,有可能把很多没有紧密关系的表关联在一起,导致一个数据表更新带动数十个更新,性能低下。等等。

上面就是先有鸡和先有蛋导致的不同分析设计实现系统。两者系统当然先有数据表入手简单,但是随着系统复杂维护性下降;而先有领域模型对象的设计入手复杂一点,但是对于复杂系统有好处,因为它不怕系统复杂,随着系统规模扩展,开发效率不会降低。

smcdl
2016-06-06 14:14

谢谢您的回复,我对领域驱动设计理解得不够透彻,所以就像我之前回复的,如果就是进入到操作层面,那么通常的操作流程是像我描述的那样吗?对于聚合我产生了另一个问题,无论是Hibernate还是JPA这类ORM都有一对多多对多等关系,可以从数据库中直接拿出一个对象树出来,那么这个根对象还是Entity而不是Model对吗?还是需要在领域仓储(Repository)中转换成对应的Model对吗?
另外,领域驱动设计里所说的领域层中包含的“实体”,无论从哪个方面来看都很像ORM中的与数据表对应的对象,那么这个“实体”到底是Model呢还是Entity呢?
[该贴被smcdl于2016-06-06 14:24修改过]
[该贴被smcdl于2016-06-06 14:25修改过]

3Go 1 2 3 下一页