锁定老帖子 主题:基于DDD项目的设计总结
精华帖 (0) :: 良好帖 (3) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2009-03-19
最后修改:2009-06-22
• 有助于团队创建一个业务部门与IT部门都能理解的通用模型,并用该模型来沟通业务需求、数据实体、过程模型。 • 模型是模块化、可扩展、易于维护的,同时设计还反映了业务模型。 • 提高了业务领域对象的可重用性和可测性。 二、领域的分层架构 在Eric Evans《领域驱动设计--软件核心复杂性应对之道》中对领域的分层架构如下: • 用户界面(表现层):负责给用户展示信息,并解释用户命令。 • 应用层:该层协调应用程序的活动。不包括任何业务逻辑,不保存业务对象的状态,但能保存应用程序任务过程的状态。 • 领域层:这一层包括业务领域的信息。业务对象的状态在这里保存。业务对象的持久化和它们的状态可能会委托给基础设施层。 • 基础设施层:对其它层来说,这一层是一个支持性的库。它提供层之间的信息传递,实现业务对象的持久化,包含对用户界面层的支持性库等。 三、如何创建领域模型 • 寻找概念类 • 将其绘制为UML类图中的类 • 添加关联和属性 四、领域模型的开发步骤 • 对领域进行建模 • 设计 • 开发 • 单元测试和集成测试 • 基于设计和开发来完善、重构领域模型 • 使用更新的领域模型重复上述步骤 五、实际项目设计 1、层次结构: 2、层次之间的交互 A、页面提交表单数据到Action,Action创建DTO对象并设置相应属性值为表单数据 B、Action传递DTO对象给Facade C、Facade中套用ServiceTemplate事务模板以加入事务管理,在ServiceTemplate中根据具体业务调用Factory或Reposistory,分别create或者load出DomainModel对象 D、Facade传递DomainModel对象给Service E、Service执行具体业务逻辑(调用DomainModel对象相应的业务方法) F、Service调用Reposistory对状态已改变的DomainModel对象进行持久化操作(调用相应DAO) 注: 在Facade或Service中如果需要查询DomainModel对象中的属性值,调用DomainModel对象的getDataInfo()方法得到DataInfo对象,通过DataInfo对象查询所需数据,包括Service返回给Façade业务处理结果中所包含的业务数据。 3、对于DomainModel的设计 DomainModel基于贫血模型来设计。在Robbin《总结一下最近关于domain object以及相关的讨论》一文对于贫血模型领域的切分原则写到: 引用 Rod Johnson提出原则是“case by case”,可重用度高的,和domain object状态密切关联的放在Item中,可重用度低的,和domain object状态没有密切关联的放在ItemManager中。
我提出的原则是:看业务方法是否显式的依赖持久化。 在该项目中DomainModel内的业务逻辑方法没有任何对DAO接口的依赖,如果需要对DomainModel进行持久化操作全部由Service调用Reposistory的store()方法进行处理,对DomainModel的持久化操作已全部封装于Reposistory中。DomainModel只提供改变自身状态的业务处理方法。 4、对DomainModel的访问原则 A、必须从领域模型的根部操作模型的各个属性 例如一个领域模型结构如下: public class PersonDomainModel { Person person; Bank bank; public void modifyPerson(String name, String age) { this.person.setName(name); this.person.setAge(age); } } 操作该领域模型的person属性只能通过modifyPerson()方法进行,而不能直接调用person对象的setter方法。 B、必须保持领域模型的完整性。最初由Factory构造一个模型的时候,就必须将其进行完整的初始化,而不是只构造一部分,然后在接下来的处理过程中逐步完善。 5、Factory和Reposistory的职责 Factory只负责领域模型对象的创建(从无到有); Reposistory对持久化进行了封装,它操作的是已存在的领域模型对象(从数据库中读取数据or重新持久化到数据库) 6、项目待优化部分 在Service调用Reposistory的store()方法进行持久化操作时,如果某个业务仅对DomainModel的一部分属性进行了修改,在持久化到数据库中时仍然会将DomainModel的所有属性全部进行一次update操作。这样的数据库操作没有必要,只需对DomianModel中修改过的属性进行持久化操作即可。可以考虑在DomainModel上提供一个类似保存所有修改属性的列表,在Reposistory持久化时仅对该列表中的修改属性进行操作。 参考资料: 1、Eric Evans《领域驱动设计--软件核心复杂性应对之道》 2、Robbin《总结一下最近关于domain object以及相关的讨论》http://www.iteye.com/topic/11712 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2009-04-12
我在看领域驱动设计这书,我觉得书中的方法隐含了一个潜在的前提:客户十分配合
在官僚机构例如政府的项目中,建立一种统一中间语言和客户用来精确沟通只会把客户惹恼"我tm一天挺忙还要记住你这些东西" 领域模型是天然的将领域驱动设计过程和实现绑定的工具,如果不能再需求时期建立DSL,如果还是按照原有的需求模式进行,而后期用领域模型来思考问题是没有意义的,因为很可能存在很多无法映射到需求的无意义的领域模型,所以沟通还是主导的\最难迈的一步. |
|
返回顶楼 | |
发表时间:2009-04-12
unsid 写道 领域模型是天然的将领域驱动设计过程和实现绑定的工具,如果不能再需求时期建立DSL,如果还是按照原有的需求模式进行,而后期用领域模型来思考问题是没有意义的,因为很可能存在很多无法映射到需求的无意义的领域模型,所以沟通还是主导的\最难迈的一步.
在开发过程中来不断地完善和重构领域模型,不过开发人员比较痛苦。 |
|
返回顶楼 | |
发表时间:2009-05-19
引用 6、项目待优化部分
在Service调用Reposistory的store()方法进行持久化操作时,如果某个业务仅对DomainModel的一部分属性进行了修改,在持久化到数据库中时仍然会将DomainModel的所有属性全部进行一次update操作。这样的数据库操作没有必要,只需对DomianModel中修改过的属性进行持久化操作即可。可以考虑在DomainModel上提供一个类似保存所有修改属性的列表,在Reposistory持久化时仅对该列表中的修改属性进行操作。 Hibernate中,配置一个entity的类属性为dynamic-update="true",最好顺带再加上dynamic-insert="true"。 |
|
返回顶楼 | |
发表时间:2009-05-19
沟通是必然的。无论是什么项目管理方法,现在都强调沟通。如果客户不重视,不沟通,那么项目失败是必然,成功才是出了问题。
不过沟通未必设计人员直接和客户沟通。可以安排专门的人员和客户沟通,编写需求列表,然后和程序员去讨论。 |
|
返回顶楼 | |
发表时间:2009-05-19
icewubin 写道 引用 6、项目待优化部分
在Service调用Reposistory的store()方法进行持久化操作时,如果某个业务仅对DomainModel的一部分属性进行了修改,在持久化到数据库中时仍然会将DomainModel的所有属性全部进行一次update操作。这样的数据库操作没有必要,只需对DomianModel中修改过的属性进行持久化操作即可。可以考虑在DomainModel上提供一个类似保存所有修改属性的列表,在Reposistory持久化时仅对该列表中的修改属性进行操作。 Hibernate中,配置一个entity的类属性为dynamic-update="true",最好顺带再加上dynamic-insert="true"。 我们目前用的是ibatis,hibernate写出来的hql dba不大好调优。 |
|
返回顶楼 | |
发表时间:2009-06-17
最后修改:2009-06-17
就楼主贴的图为例,我不知道是不是Eric那本书里的。 文字说的是领域建模,而例子却完全不是这么回事。
领域建模,至少是 Person类,而不是多了个后缀的 PersonDomainModel 类。 领域建模有一点要求 Data, Behavior 封装在一个类或者接口中,对使用者而言,对象是自我描述,自我行为的。create,load 可以由 repository 进行, 但update,save,delete等在调用角度上,必须由对象自己完成(或者由框架提供)。 形如: Person person = repository.load( id); person.setAge( 23); person.update(); //也可以由框架来做 再说例子中那么多Action,Service,Facade, DataInfo类,完全还是约束于框架,根本不是在领域建模。 补充一下:存在 Action,Facade,Service 也许可以划归 DomainModel 外围, 但可能我比较理想化。 我认为表示层按DomainModel 可以设计为 XXXPage 类,由formBean,status等属性,onCreate,onView,onQuery 等Event构成完整的领域模型, 而不是 Action.execute 方法; Application 层也一样,再前进一把,也能抽象为本层的 Domain Model。 也许真的比较理想化。-_- |
|
返回顶楼 | |
发表时间:2009-06-17
最后修改:2009-06-17
raymond2006k 写道 就楼主贴的图为例,我不知道是不是Eric那本书里的。 文字说的是领域建模,而例子却完全不是这么回事。
领域建模,至少是 Person类,而不是多了个后缀的 PersonDomainModel 类。 领域建模有一点要求 Data, Behavior 封装在一个类或者接口中,对使用者而言,对象是自我描述,自我行为的。create,load 可以由 repository 进行, 但update,save,delete等在调用角度上,必须由对象自己完成。 形如: Person person = repository.load( id); person.setAge( 23); person.update(); 再说例子中那么多Action,Service,Facade, DataInfo类,完全还是约束于框架,根本不是在领域建模。 不完全是,DDD中也不反对使用一个service类来处理业务逻辑,没有严格限定说一定要把Data和业务逻辑封装在一起吧。大家大概发现了,我这里写的是业务逻辑,而不是Behavior,我认为这两个概念还是分开说得好。一般来说有很多操作都是业务逻辑,而没有那么多的Behavior,而业务逻辑的操作的复用就是个很大的问题。 PS:我最近正好在翻这本书。 |
|
返回顶楼 | |
发表时间:2009-06-18
你在哪里听说的DDD不反对使用service类来处理业务逻辑了?别告诉我是Domain Service啊。。。
|
|
返回顶楼 | |
发表时间:2009-06-18
service是对行动的封装,没有主属,可以分布在application,domain层.
factory也不是必须的,在需要的情况下. application的service处理transaction.也可以直接调用repository. domain和repository的分离也不对.因为没有aggregate的概念. dao在jpa等的支持下,也可以不要. |
|
返回顶楼 | |