请教banq老师一个repository的问题


repository是针对聚合跟建立还是针对实体对象啊?
比方说员工是聚合跟,考勤记录是员工的一个属性,是个list;
我是对应聚合跟 Employeerepository
我想添加一条考勤记录的话,
employee = Employeerepository.getById();
list = employee.getRecord();
list.add();
Employeerepository.update();

这样对吗?
要是对的话,虽然employee在缓存中,不用每次都查数据库取得,但是每次update,我用的是hibernate,数据库会执行很多无用的语句,insert 然后在update 不如直接用dao就执行一条insert快。请banq老师仔细说说。

2011年04月10日 10:10 "@xiaolongnvo"的内容
repository是针对聚合跟建立还是针对实体对象啊 ...

关键这个问题弄清楚,聚合和实体的区别是边界大小不同,聚合是一个根实体为中心,带着很多小卫星。

这个我明白。请banq老师看看下边的处理对吗?要是不合适,应该怎么处理?我觉得给个具体的方法,能叫我更好的理解。

2011年04月10日 10:10 "@xiaolongnvo"的内容
比方说员工是聚合跟,考勤记录是员工的一个属性,是个list ...

如果你设计成,员工是考勤记录的聚合根,那么下面实现方法被局限这个设计边界中,你如果又使用Hibernate之后,边界就越小,就象前面有很多定语,那么你就会被限制,如果你这时欲望又很多,就痛苦疑惑了。

解决办法:权衡你的欲望合理与否,如果遵从自己的欲望(不想数据库执行太多无用语句),那么就重新考虑前面的定语,首先Hibernate是否可优化,或不用?再次是否聚合根设计有问题?

我认为,聚合根设计有问题,将考勤记录划为员工聚合边界内,说明他们之间关系紧密,那么如果员工的销售记录是否也划在其中呢?

领域建模有三个大小不同边界,领域边界,聚合边界,类边界。哪些应该放在哪个边界中,是有反复考量的。

当你放入一个对象进入边界时,有一个反方向力在对抗它:就是低关联,高聚合。所谓高聚合,不是一般的聚合,而是一种最紧密的组成关系,没有你我就活不了,否则不用划。

因为业务功能发生关系的就尽量不用划入聚合边界,因为业务活动一旦发生,他们就自然产生关系,比如员工一旦在考勤这个活动场景中,就自然和考勤发生关系,并自然拉下考勤记录这泡屎。

而我们传统数据库思路,就只看到考勤记录这个静态存活时间很长的这泡屎,然后把员工和屎划上关系,并且强调“就是你拉的屎”,他根本不关系是否看到“考勤”这个蹲下拉屎的动作,依据倒推原则“有记录就有考勤”,那么考勤动作谁来设计呢?上帝做吗?

有可能以上回答你不是很理解,如果你想在现有设计+Hibernate这些定语限制下,又想操数据库那份心,我也没办法帮你,因为对于我来说,是瞎操心。


2011年04月10日 11:10 "@banq"的内容
因为业务功能发生关系的就尽量不用划入聚合边界,因为业务活动一旦发生,他们就自然产生关系,比如员工一旦在考勤这个活动场景中,就自然和考勤发生关系,并自然拉下考勤记录这泡屎。

而我们传统数据库思路,就只看到考勤记录这个静态存活时间很长的这 ...


意思是不是:不要把考勤记录,销售记录聚合到员工里,独立开。这样做的话,我觉的又回到数据库上了。要是用ddd的话应该怎么设计这个聚合啊? 这个弯我就是绕不过来。记录考勤这个动作,是个定时服务。每天晚上12点记录当天的考勤。

2011年04月10日 12:33 "@xiaolongnvo"的内容
不要把考勤记录,销售记录聚合到员工里,独立开。这样做的话,我觉的又回到数据库上了。 ...

这句话怎么理解?注意我上面一句话:
因为业务功能发生关系的就尽量不用划入聚合边界,因为业务活动一旦发生,他们就自然产生关系,比如员工一旦在考勤这个活动场景中,就自然和考勤发生关系,并自然拉下考勤记录这泡屎。

两者独立开后,通过"考勤"这个功能实现会将两者联系一起,比如你做了一个页面,上面有”考勤“这个菜单,员工选择它,就完成了考勤,同时产生考勤记录,然后你用数据库或文件保存一下这个员工的考勤记录。

用数据库作为实现保存,不是用数据库来主导设计。两者有区别,好好体会一下。

[该贴被banq于2011-04-10 13:06修改过]

employee = Employeerepository.getById();
list = employee.getRecord();
list.add();
Employeerepository.update();

[该贴被showerxp于2011-04-10 17:02修改过]

很多东西的关联不是必然存在的,比如你说的员工和考勤,这些关联都是在一定的条件或者一定的场景下关联。比如你的员工,只有在考勤的场景中,这两个才会有联系。在其他场景,他们是没关系的。另外DDD的聚合根要谨慎使用,如果使用不当,不当达不到聚合的作用,反而会搞成高耦合。所以关联是有条件的,DDD的聚合讲的是一种强依赖,比如人和头一样,没头了,人也是不能有生命的,但是不考勤,员工还不照样活着?

随便说说一个菜鸟的理解。
在特定的具体的场景下员工才会和考勤记录发生关系,或者员工才会和销售记录发生关系,
这个场景就指service,如果不考虑service而是把考勤记录,销售记录一股脑的都静态的和员工这个类发生关联,只不过是功能代码的堆砌而已,无论你是否需要他都在里面。

考勤记录/销售记录属于员工,但是员工不一定时时刻刻都非要有销售记录和考勤记录才行。
[该贴被pye于2011-04-11 09:39修改过]

领域模型,是针对客观世界建模的产物,不能因为一时之效率而随意讲设计好的模型穿插数据库的CRUD代码。就是说,要保证领域模型的纯洁——反映客观世界的业务流程。所以我们引进领域概念的资源库来解决领域对象的保存、获取等问题。对于这个例子来说,资源库的行为可能有add考勤、remove考勤、find考勤……

前面大家已经说了,聚合是一种强关联。我想说的是,这个强关联概念估计DDD是直接从uml引进的,是因为有谁的存在而存在。

有这种强关联的概念,我们在看看楼主的问题——“repository是针对聚合跟建立还是针对实体对象啊?”我认为资源库就是针对聚合根建立的。

聚合根是老大,它将它周围那些“小卫星”视为己物,不容别人侵犯。举个例子。美女是个聚合根,她住在A处。你和美女交谈,死缠烂磨知道她住在A处。然后你私底下将美女住在A处高速你的死党,结果一传十就传开了。问题是传的过程中,某人传错了,把美女住在A处说成B处。居委会居然同意这种流言,将美女住在B处登记在案。事实上,我们的程序很可能就是那个部分青红照白的“居委会”。

要解决这个问题两点,一是美女根本就不随意外传她的住地。居委会要知道美女地址只能问美女。二是,美女告诉你住地发表声明,大概意思是,她与你的谈话最终解释权归美女,谈话完毕,你把A地说成任何地点都与她没有关系(也就是给了个地点对象拷贝)。

另外,员工和考勤是不是聚合关系也没有定论,关键看问题域的关系。比如,财务部门每月造工资表。如果该员工没有考勤表,财务部门就当非员工处理,不给做工资表。这样,员工和考勤表无疑成了聚合的强关联了。

2011年04月10日 12:43 "@banq"的内容
句话怎么理解?注意我上面一句话:
因为业务功能发生关系的就尽量不用划入聚合边界,因为业务活动一旦发生,他们就自然产生关系,比如员工一旦在考勤这个活动场景中,就自然和考勤发生关系,并自然拉下考勤记录这泡屎。

两者独立开后,通过"考勤" ...

banq老师看看我这样理解对不对。
class employ{

}
class RecordWork{
Date comedate;
Date godate;
employ em;
}

// 记录考勤场景类
class recordEmploy{
private recordWorkReposity rwr;
void recordEmployWork(){
r = recordWorkFactory.create();
rwr.save(r);
}
}
在员工类里没有考勤的关联,只是单向关联,查看的时候从recordWorkReposity 查询。

2011年04月21日 23:04 "@xiaolongnvo"的内容
记录考勤场景类 ...

记录考勤场景类 在服务中实现,而不是仓储,仓储只是一种结果记录。

2011年04月22日 19:45 "@banq"的内容
记录考勤场景类 在服务中实现,而不是仓储,仓储只是一种结果记录 ...

// 记录考勤场景类
class recordEmploy{
private recordWorkReposity rwr;
void recordEmployWork(){
r = recordWorkFactory.create();
rwr.save(r);
}
}
recordWork employ 是俩个独立的聚合体;所以俩个都有仓储;
记录考勤场景类 也可以理解成服务。
由于recordWork employ 是单向多对1 的关系。
增加recordWork记录 我就在服务里直接直接引用仓储完成。不可以吗?
还有我有点不明白 场景这个东西的含义了。比方说人 在家的行为 跟在公司的行为 都是人的行为。我要是设计人这个实体的时候是 class person implements Home ,Factory {}
还是设计俩个人在家,人在公司俩个场景? class person {} 在家跟在公司的行为不在person身上实现。而是 把person 当参数传入场景类里?
class AtHome implements Home{
bringUp(person);
}