锁定老帖子 主题:贫血的Domain Model
该帖已经被评为精华帖
|
|
---|---|
作者 | 正文 |
发表时间:2008-05-23
kabbesy 写道 taowen 写道 我想robbin的意思其实是如果只有一个client,也就是在只有web层用它的情况下,service层除了啰嗦没啥价值,不如直接合并进web层。我对这个问题的看法是,要看service层中的具体服务到底有几个用户。如果到处都是只有一个用户的service,我们还要抽象出好多接口和对象来提供这些服务,不如直接在用的地方写就好了。在实际的,简单的web项目中,好像取消service层,让service层的用户也就是web层来实现事务控制安全控制好像更符合务实的精神。其实有三个选项:1、分层,2、分对象,3、分方法。简单情况下,取消service层,把起职责散布成web层的一些对象乃至成为action的一个方法,也未尝不可。不过没有具体实践,还要观察观察。
domain是不应该太贫血,但也没必要单纯为了rich domain而取消service层。 假设取消掉service层: 首要问题就是domain之间的交叉依赖,而在传统service层中,domain之间的关系从来都是交给具体service去完成的,service搞的再烂,也不会把domain搞烂; 然后是事务边界带来的bad smell(虽然将持久化设备注入给domain也不见得是坏事,但习惯上总觉得不那么好) 然后是如何为prototype bean进行注入; 最后还有诸如团队协作这样的麻烦,逻辑过于集中后,协同开发的确成为了麻烦事情。 所有这一切,只换来一个“逻辑集中”的优势,不用再考虑哪些方法该调用domain的,哪些是service的。而这些完全可以被合理的方法命名和编程规范所解决。 取消service层追求完全的rich domain,实在是弊大于利。 似乎你说的service和我说的还不大一样,呵呵。 DomainObject之间的交互是不需要Service的。 |
|
返回顶楼 | |
发表时间:2008-05-26
taowen 写道 to coolnight:能不能举一个你们公司的Rich Domain Model的例子,以及它们是如何被大家废弃的。
sorry 看到这个较晚, 大致回复下: 我们的系统有很多模块组成, 各模块基本上通过数据库来共享信息。 主要的模块大致有: 核心系统(非web), 网站、 bbs、 网站后台,核心系统后台,BI, 推广员等等 原来的打算是写个rich domain model供各模块来使用,以便代码重用减轻个模块开发的工作量 一个简单的例子, User 原有 changePassword, getFriends, addFriend ... 等等方法 撇开配置以及获取User对象的复杂性不谈, 实际开发中发现, 这些东西重用的地方太少了, 对网站来说很好的rich domain model, 在网站后台里面就麻烦,很多方法在那里根本就是对后台 开发人员的干扰,而很多方法对核心系统、BI等等根本就毫无用处。 而且由于网站之类的web系统, 其功能变化很快, 今天一个样子明天完全有可能是另外一个样子了, 新招个策划都可能提出一堆的改动来, 还有很多临时性的功能, 最后真正在各模块之间共享 的就是最贫血的domain model, 基本上就是表的映射, 连关联都给废了各处自行维护了 因为系统数据量比较大,所以性能问题也受到比较多的关注, 在系统的关键部分, DBA说了算,OO靠边站 实际上我在几个公司呆过 也曾试图写出比较rich的domain model, 但是只要项目的需求变更的比较频繁, 那么rich domain model维护的成本就会很高, 而且想重用的想优雅的地方最终大部分变成了摆设, 而需求变更不频繁的项目, 太少太少了 |
|
返回顶楼 | |
发表时间:2008-11-26
我觉得也可以专门抽象个查询组件来实现类似的功能。数据量大的情况下,我一般采用查询的方式。DDD中也说了,同一种模型有不同的实现,查询也可以算一种实现。
|
|
返回顶楼 | |
发表时间:2009-01-21
coolnight 写道 robbin 写道 taowen 写道 Robbin能否举一个例子如何像ActiveRecord那样用静态方法调用领域逻辑。
public class Employee { @OneToMany private Set<Task> tasks = new HashSet<Task>(); public Set<Task> getProcessingTask() { ...... } public static getAllEmployee() { ...... } } 比方说类似这样的,如果不依赖特定对象实例的方法,直接用静态方法如何?如果getProcessingTask用到其他对象的方法,如果是依赖对象状态,可能就是方法参数传递进去,如果不依赖,直接调用该对象静态方法。 不知道这样去用,会不会有什么问题。自从IoC兴起以后,貌似就没有人这样去用了,大家都极力避免静态方法的出现。 java里面使用静态方法的不便之处很多, 比如说不容易扩展, 不容易被替换等等,而ruby的特性决定了这些不是很大的问题。java里面这种形式的rich domain model的事务也不容易被管理 在java里面用ioc来管理依赖是比较好的做法, 很难扔掉;而且 ioc也确实带来很多的好处 一个复杂的系统里面,真正最稳定最一致的东西是什么呢, 其实正是那些 贫血的domain model! 除非需求非常明确, 系统在设计期就能定下rich domain model,最好对于独立的model很少有团队协作,这种 情况下rich domain model才有优势, 至少少了一个dao的依赖。 但是这样严格的场景太罕见了, 大部分情况下需求经常在变, 经常要加上新的功能, 这个时候就会发现,如果是rich domain model的设计, 对domain model的不断的修改就成了一个梦魇! 如果有多人协作完成系统的不同部分,互相之间要share domain model的时候, 那rich domain model就更加难以运用了! 如果还要用Service层进行事务管理的话,那很多时候 就必须把rich domain model里面的功能在Service层全都包装一遍, 那么为什么不直接在Service层直接实现 rich domain model的功能呢? 我们公司现在的产品就是这样, 开始的时候就是贫血domain model和rich domain model都有, 越用就越发现贫血模型的好处。现在 rich domain model的功能大部分处于废弃状态, 真正有用的,基本就是 贫血 domain model, 或者说po, 加上一个薄薄的dao层, 然后系统的各个部分各自使用各自的service层,很清晰很简单很有效!! 但是我认为这里存在一个问题,就是如果系统中某个逻辑要求处理一个抽象的类的实例,即要求处理的对象具有多态的特征(指的是由Manager实现的行为),此时,难道要直接去处理因此得来的Manager的继承层次? 不知道我的意思你是否能够明白,就像你上面讲的那个Employee,如果这个人员分为普通人员,特殊人员,他们的addFriend 行为是不一样的,这里你的Manager会不会按照两种不同的人员来分别处理?换作另一个地方,某个逻辑要求无分别的处理不同类型的Employee.AddFriend,那这里我要传过来什么?Manager,还是Employee?如果是Manager,这种层次会让我有非常不好的感觉,如果是Emplyee,那么我就要在这个新的地方重写AddFirend的逻辑.请替我解解惑....在这里,我认为最好是无差别的应用Employee的对象,不过我确实是不知道你的Manager是如何写的. |
|
返回顶楼 | |
发表时间:2009-01-21
robbin 写道 taowen 写道 Robbin能否举一个例子如何像ActiveRecord那样用静态方法调用领域逻辑。
public class Employee { @OneToMany private Set<Task> tasks = new HashSet<Task>(); public Set<Task> getProcessingTask() { ...... } public static getAllEmployee() { ...... } } 比方说类似这样的,如果不依赖特定对象实例的方法,直接用静态方法如何?如果getProcessingTask用到其他对象的方法,如果是依赖对象状态,可能就是方法参数传递进去,如果不依赖,直接调用该对象静态方法。 不知道这样去用,会不会有什么问题。自从IoC兴起以后,貌似就没有人这样去用了,大家都极力避免静态方法的出现。 我昨天也在思考这个问题,如果是静态方法,可以很大程度上减轻对象的行为,因为像GetXX这些方法我认为与具体的实例相关增加了领域对象的复杂程度,领域对应该最好只是专注与自身的状态.但是Ioc的动态注入实在是个好东西,真是不知道如何取舍好. |
|
返回顶楼 | |