Potala(2)——Domain Model

  根据Eric Evans在《Domain-Driven Design》中的说法,所谓Domain,简单地说就是指问题域;Domain Model就是和Domain中特定问题相关的模型。

  为什么要Domain Model?因为它相对于原来的Transaction Script方式(即传统的那套Entity+DAO+Service方式),能够比较好地处理复杂的业务逻辑。以下是摘自《Patterns of Enterprise Application Architecture》的一段原话:The value of a Domain Model lies in the fact that once you've got used to things, there are many techniques that allow you to handle more and more complex logic in a well organized way. As we get more and more algorithms for calculating revenue recognition, we can add these by adding new recognition strategy objects. With the Transaction Script we are adding more conditions to the conditional logic of the script.


Domain Model的各种角色:

  领域模型主要由以下角色组成的:

  Entity:具有唯一标识的对象,且该标识和该对象的属性值分离;

  Value Object:主要是一些属性值定义的对象,比如说Address等;

  Factory:负责Entity和Value Objec的创建(不是特别复杂的情况下不常见);

  Repository:封装持久层框架,管理Entity的集合,定义查找和删除等方法;

  Service:它实现整个业务逻辑的工作流,一般负责一些无法指派给单个Entity的行为。

  按Eric Evans的说法,Domain Model还应该包含Association和Aggregation,但这些更多地体现着Entity和Value Object之间的关系,虽然属于设计时应该仔细考虑的方面,但个人觉得把他们放进来有点牵强。


开发Domain Model:

  结合《Pojos in Action》和《Domain-Driven Design》的观点,我个人认为比较行之有效的一套方法是:

  先识别一个用户用例,比如下单动作等;

  然后从中去识别出Entity和Value Object(这一步应该比较容易);

  接着去考察它们之间的关联关系(比如如何在各个Entity间提供导航等)和聚合关系(确定Entity和Value Object的操作边界,比如是否提供级联删除等);

  识别出Service方法,尽量把能分发给单个Entity或者Value Object的方法分发出去(尽量少担心这样会使Entity过于“肥胖”,事实上,如果它们的确过于“肥胖”,再进行重构也不为迟)。这一步通过TDD的方式来Mock对象会对开发带来极大的便利,因为这样可以进来减少对象间依赖,从来可以很轻易地做到自顶向下的开发。

  最后一步,完成各个对象的功能,并使他们功过单元测试(Repository需要进行集成测试)。


一些值得注意的问题:

  首先是关于Domain Model粒度的问题。一般来说,粒度越细容易增加整个对象模型的复杂性,但却可以提供更好的重用性。我个人比较倾向于相对细些的模型,因为系统的复杂度一般都是由业务逻辑的复杂性,而不是对象模型的复杂性造成的,所以代码的重用应该成为我们的第一考虑。另外,目前日臻完美的持久层框架也为我们映射细粒度的Domain Model提供了一个比较好的条件。

  关于Entity调用Repository方法的问题。 这个问题有些争论,有人认为它们不应该知道有Repository,但我觉得在处理一些不会引起歧义的逻辑时,在Entity来调用Repository方法也未尝不是一种很好的解决办法,但这种方式也不宜用的过多。另一个问题是在Entity中如何调用Repository:Entity一般由持久层框架创建,所以在Entity中添加一个指向Repository的方法显然是不合适的。比较好的解决方法是把Repository作为一个参数传到Entity要使用它的方法中去。

  业务逻辑的组织问题。对复杂易变的业务逻辑,最好用Strategy方式抽象出一个Policy类进行单独地存放。这样做有几个好处:第一,使逻辑一目了然;第二,可以比较方便地和业务人员讨论如何对这些逻辑进行处理;第三,能够比较灵活地应对业务逻辑的变化。比如在我们的项目中,对于不同商品和不同用户的定价策略就相当复杂,而且前前后后也经过几次变化。如果不进行单独的抽象,修改这些代码将是件很恐怖的事情。

     另外关于关联和聚合边界在设计的时候也需要特别注意,否则极其容易引起非常复杂的数据库事务。关于这个问题将在事务管理中进行阐述。

   

  大概先写这些吧。以后想到了或者遇到了什么其他的问题再来补好了~~

posted @ 2008-12-13 20:35  Marco Zeng  阅读(1148)  评论(12编辑  收藏  举报