`
taowen
  • 浏览: 193580 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

领域模型的价值与困境

阅读更多
很久以前大家就关于这个方面有很多讨论了。前两天我又挖了一个坑来集思广益,非常感谢没有把我的帖子投为新手帖的同志。我不是在装傻,只是想让大家跳出自己的立场,从根本的价值出发来考虑问题。之前有很多讨论,都是在讨论我又发明了一种新方法可以让领域模型充血啦,等等之类的。当提出一个解决方案的时候,一定要有明确的问题。那么领域模型的价值是什么?为什么没有被广泛应用,其困境在哪里?

价值

数据,一定是数据。做企业系统,最核心的东西一定是数据。关于数据,人们有许多需求,但是最根本的一点就是,数据要是对的。在关系数据库的上下文下,为了保证数据是对的,我们有外键,我们有COLUMN的数据类型,我们有主键,我们有constraint,我们有很多很多。但是很多时候还不够,一堆数据在业务上是不是合法的,超过了上述的检查方法的能力范畴。这个时候,以DBA为中心的思考就会导致:我作为DBA,管理这些数据,如果数据出了问题,那就是我的责任了。所以我必须要阻止愚蠢的事情,而我显然是最知道什么是正确数据的人,所以你们(程序员)要访问我的数据,就必须通过我的存储过程。

这种方式显然遇到了问题。问题是很多方面的,有人员素质问题,有工具支持问题。更重要的是,虽然存储过程起到了防火墙的作用,阻挡了外界可能的对数据一致性的破坏,但是其内部却是脆弱的。数据对于包裹它的存储过程都是开放的,写存储过程A的人,可能对数据的假设与写存储过程B的人对数据假设是不一致的。两个人必然只有一个是正确的,但是从数据出发找到修改它的地方并不容易,从而给数据的质量埋下了隐患。

存储过程的问题,就是面向过程的代表。面向对象的主要特征,封装就是为了解决这个问题发明的。把数据放置于对象内部,要修改对象所封装的数据,就必须通过对象所提供的外在行为。有如下图所示。



回到数据的正确性这个问题。程序员不同于DBA,给出的解决方案是领域模型。其实领域模型,只是面向对象的另外一个名字而已。通过把数据封装在领域模型的内部,我们就可以限制模型的使用者对数据的修改,什么值是对的,什么样的值是不对的。具体列出来有:

构造函数
可以确保在创建的时候已经有了所有的必填项
public class Person {
  public Person(String firstName, String lastName) {
  ...
  }
..
}


无Set方法
不能任意的改变值,必须通过特定的合法性检验
public class Publication {
  private State currentState;
  public State publish(Channel to) {
  ...
  }
...
}


关联
可以保证外键,以及强制约束两个表之间数据的关系
public class Cargo {
  public void attachItinerary(final Itinerary itinerary) {
    // Decouple the old itinerary from this cargo
    itinerary().setCargo(null);
    // Couple this cargo and the new itinerary
    this.itinerary = itinerary;
    this.itinerary.setCargo(this);
  }
...
}


一致性
冗余字段的同步更新得到强制
public class ShoppingChart {
  private List<OrderItem> items;
  private int sum; //冗余字段
  public void dropIntoChart(OrderItem newItem) {
    sum += newItem.sum();
    items.add(newItem);
  }
  ...
}


当然,面向对象不光是封装一个特性,它还有继承和多态。所以作为面向对象的另外一个名字,它自然也有继承和多态这个好处。具体到程序里就是

枚举值
不要通过对枚举值的判断来决定程序的路径
// 过去
public void publish(ChannelType channelType, Publication publication) {
  if (channelType.equals(ChannelType.RETUERS)) {
    ...
  } else if (channelType.equals(ChannelType.BLOOMBERG)) {
    ...
  } ...
}
//现在
public interface Channel {
  void publish(Publication publication);
  ...
}
public class RetuersChannel implements Channel {
  ...
}
public class BloombergChannel implements Channel {
  ...
}


数据的含义
另外一个好处是,对数据的访问被集中起来了。所以,从数据出发,很容易发现计算出值并修改它的地方。这就方便了我们去理解数据的含义。数据本身是没有任何意义的,数据只有被使用才有意义。只有理解了数据的上下文的含义,才能编写更多的行为去操作数据。在写新的行为的时候,我们必然要参考过去的行为是怎么理解数据的含义的。这个查找的过程越容易,越有助于我们写出正确的逻辑,也越有助于我们发现过去已经写过一样的行为了,那我就不用写了,也就是所谓的复用。

所以,理论上来说,面向对象或者说领域模型是非常适合我们的日常的企业信息系统开发工作的。但是,实践中,却遇到了很多问题。

困境

框架的约束
如Robin所言
robin 写道
如果你用的是Spring,没啥说的,必须贫血,你想充血也充不起来;
如果你用的是RoR,也没啥说的,直接充血,你想贫血也未必贫得下来;

这就是一个基本事实。Spring作者也坦言(Rod Johnson, JAOO, 2006),Spring的编程模型基本上是EJB的延续。从架构和分层的角度,它们是一脉相承的。这种分层的架构决定了,行为在Service里,数据在Entity里。这种做法成为“最佳实现”,不是偶然的,是框架设计给你的必然结果。矛盾的集中体现在于Entity无法被注入(当然你可以注入,但是这是不推荐的做法)。Spring后来尝试修复这个问题,引入了AspectJ来做Entity的注入。不过仍然不是主流,因为框架的阻碍只是一个小问题,更大的问题在于这个Java的OOP实现本身就有问题。

语言的约束
在很多的讨论中,反对“充血”领域模型的同志都提到。把逻辑集中到领域模型中,会造成类的膨胀。在我个人的实践中,近千行的Entity类定义也是有的。而且这些行为往往不稳定,往往流程高度相关,复用程度并不是想象的那么高。
原因是因为,数据并没有所谓的内在行为。你不用它,它就没有行为。所以数据有什么行为,其实是使用者赋予的。而同样的数据往往会在不同的场合(context)下被使用。正如这位同志所言:
coolnight 写道
我们的系统有很多模块组成, 各模块基本上通过数据库来共享信息。
主要的模块大致有: 核心系统(非web), 网站、 bbs、 网站后台,核心系统后台,BI, 推广员等等
原来的打算是写个rich domain model供各模块来使用,以便代码重用减轻个模块开发的工作量
一个简单的例子, User 原有 changePassword, getFriends, addFriend ... 等等方法撇开配置以及获取User对象的复杂性不谈, 实际开发中发现, 这些东西重用的地方太少了,对网站来说很好的rich domain model, 在网站后台里面就麻烦,很多方法在那里根本就是对后台开发人员的干扰,而很多方法对核心系统、BI等等根本就毫无用处。

所以上面所画的图就得改一下了:



同样,很多同志也发现了这个问题,并给出了解决方案
Quake Wang 写道
用mixin实现领域模型是最简洁的做法, 但是受到Java语言的限制,得用大量mark性质的interface和composite模式,反而会让整个结构变得复杂。
相比C#的namespace或ruby自定义dsl(acts_as_xxx),在java玩领域模型需要更多的功力,推荐一下Rickard Öberg的qi4j,它将composite oriented发挥到了极致:
http://www.qi4j.org/

ray_linn 写道
我建议用C#的扩展方法,或者Java用mimix(不知道打错没有),Domain还是POJO,方法在适当的时候“黏合”(C#通过 namespace引用)到POJO上,让POJO “充血”,而在充当VO,DTO的时候,POJO又可以“放血”回到“贫血的”状态上。

这个问题基本上是暴露了Java的OOP实现的缺陷。C#的Partial Class, Extension Method和Ruby的Mixin就是对这种“一个class定义一切”的做法的改进,允许行为被分片定义,而不是集中定义在一个文件中。

现状
很多同学都谈到现状不是完全的没有领域模型,而是所谓的贫血的领域模型。之所以会这样,就是前面所说的困境。正如很多朋友所说的,这未必是一件坏事,比如可以避免核心的domain过度膨胀。不过也未必是一件好事,理由我能想到这么几点:

越俎代庖
这是我们的DAO经常干的事情。比如我们有两个domain,Publication(一份文档)和Distribution(一次分发)。它们两者之间是聚合关系,也就是distribution必然属于一份publication。如果是重写的领域模型,我们可以通过publication来控制对distribution数据的添加。比如
public void distribute() {
  if (isDeleted()) {
     throw new InvalidDistributionException();
  }
  distributions.add(new Distribution(this));
  lastDistributionDate = new Date();
}

但是一旦有了DistributionDao,就不一样了。
distributionDao.save(new Distribution(somePublication));

哈哈,啥控制都管不了我了吧。很多时候Dao就是这么无法无天的。如果说domain model是数据的防火墙,那么dao就是顶级黑客。由于Entity不能注入等实现和宗教信仰上的限制,往往导致了service对DAO的滥用,就会造成上面这样的by-pass domain model的情况。

舍近求远
明明我有一个contact
public class Contact {
  private List<ContactNote> contactNotes;
...
}

但是我不能直接去取我的contactNotes(性能啊性能,hibernate会load all啊)。所以我得写个查询
from ContactNote where contacted = thisContact and ...

我有一个contact就应该能够让我
contact.allMeeetingContactNotes();

但是不行,你得
contactNoteDao.findMeetingContactNoteByContact(thisContact);

舍近求远也

职责混杂
根据我理解的Service层的现状是:有一部分是作为domain model对外的接口,提供了事务安全等服务,真正是一个“service”对web层提供服务;有的呢,则是当作一些可重用的行为被注入到其他的service之中;而有的呢,则纯粹是一些utils。当然,不过可能是我用的不对吧,或者理解有误。

距离啊距离
数据和行为距离很远。造成了不容易理解数据含义,因为你光看entity压根不知道它会被怎么用。漏掉一些servie中细微的用法,就可能会造成很大的bug。
同时这也更加让可重用的逻辑更难被发现,从一定程度上鼓励了大家各自发明,一份逻辑写n遍,还n遍都不一样。。。
当然啦,这个问题没有想象的那么大,毕竟贫血的领域模型,还是鼓励大家把“只和这个对象,不和外部接口有关的”的逻辑放到对象本身的。问题的大小,取决于团队的稳定性,素质和职业操守。

术语
如nihongye同学所说,xxxService不是domain language。当然啦,讨论这种问题最终是仁者见仁智者见智的。

解困

你真的要解困吗?其实你未必被困住了。你可能根本不需要领域模型,特别是在Java/Spring这种实现下,难以实现。正如很多同志所言,我用贫血模型用得很好。那就行,自己好,就是真的好。但是有朝一日,觉得贫血模型不再适合你了,不妨去了解了解qi4j(如果你不想换语言),或者投入rails的怀抱吧。
  • 大小: 7.9 KB
  • 大小: 12.8 KB
分享到:
评论
25 楼 yangyi 2008-12-03  
需知自然地未必是最佳的,就好像计算机总有一天可以征服自然语言,但你敢把它用在阿波罗登月上吗?如果敢的话应该是在心电感应这种操控技术发展成熟之后
24 楼 starfeng 2008-12-02  
robbin 写道
我来说几句吧:

第一、DAO层和TransactionScript层是邪恶的!

我们在2004年一直跨度到2007年讨论来讨论去,其实都有一个隐含的前提条件:你的领域模型终究无法脱离对DAO层的依赖,以及需要TransactionScript层的包裹。而这样一来,领域模型的通用性、可移植性、业务逻辑的表达能力基本全部丧失,沦为框架限制下的奴隶。

而我们看看现在Java领域的技术进步,JPA已经普及,EJB3的隐含事务管理,甚至连Spring也可以简化成@Transactional,现在已经是我们可以去掉DAO和TransactionScript的时代了。


第二、Seam在消除了DAO层和TransactionScript以后,领域模型的感觉已经呼之欲出


这个不用多说,大家自己去看Seam文档好了。我唯一想强调的是entity bean和business bean分开有没有必要性,我的看法是有必要!这还是和Java本身语言的限制有关系:

1、Java语法表达能力有限,entity bean又不得不弄一大堆getter/setter方法,都放在一个class里面,代码的可阅读性非常差

2、business bean的很多业务逻辑方法需要容器环境,不像Rails的model可以直接mixin进来

3、Java做为目前最主流的工业语言,开发团队都是大规模编码协作的,你都放在一个class里面,团队协作会遇到很大的麻烦(事实上RoR现在也有这样的问题,但是RoR开发效率高,往往不需要那么大规模的开发团队)

3、领域模型不同类别的业务逻辑可以很容易的分到几个不同的business bean里面,这样对团队协作的好处很大。


第三、不考虑框架限制,All-in-One的领域模型好不好?


比方说RoR的model就是All-in-One的,但是一旦出现可以抽象出来,比较通用的业务逻辑,我们还是会把这些逻辑抽出来,单独实现,然后再mixin回去。


所以最终我对这个问题的总结就是:

一、只要技术框架能够实现,尽量使用领域模型

二、无论Java还是Ruby,必须消灭DAO和TransactionScript

三、领域模型不必All-in-One,Java可以分割为 1个entity bean和几个business bean,而Ruby可以分割为1个model和几个mixin的module。




非常认同.
DAO消灭的原因是O/R Mapping的成熟,它已没有存在的必要.他出现的目的只是为技术服务--技术层面上SQL与Business的解耦.随着技术的成熟,他已没有存在的必要了.更准备的说是DAO担当的功能被替代掉了.
Java中的entity bean和business bean必需要分开,他们代表着一静一动
我认为要分的理由是(和robbin的会有不同,主要是不同的角度去看): OO的本质还是在按人的理解现实世界方式去组织软件世界中的数据与指令, 很明显现实世界的石头是不会动的,马路也是不会动的,他们就是Java中的entity bean.
如果只有Rich domain, 那么, 我们生活的世界就是动画世界了, 石头会主动打人,马路会自动拐弯, 转去生活在这种世界会有什么问题呢, 走路时要小心下一步会不会踩空,爬山时要担心石头会不会主动打人,你会突然发现要考虑好多意外因素啊,很麻烦,会把人累疯.这样的软件世界也会出类似情况.
23 楼 Ashela 2008-12-02  
还有,硬要充血,spirng2的@Configurable是可以实现对实体的IOC注入的
22 楼 Ashela 2008-12-02  
有个折中的办法,像pojos in action里面一样把dao的接口当成实体方法的参数,dao的职责和实体方法的需求有关,可以做到充血模型
21 楼 raymond2006k 2008-12-01  
robbin 写道
我来说几句吧:

所以最终我对这个问题的总结就是:

一、只要技术框架能够实现,尽量使用领域模型

二、无论Java还是Ruby,必须消灭DAO和TransactionScript

三、领域模型不必All-in-One,Java可以分割为 1个entity bean和几个business bean,而Ruby可以分割为1个model和几个mixin的module。





比较同意 robbin 的观点。

的确是技术或框架,限制了领域模型的应用。

当J2EE 起步时, 主流的是EJB规范. 它的不好之处就是为了Container或Server的考虑,强行在规范中分为了 EntityBean,SessionBean, 并且作为业务bean的SessionBean,除了Bean实现类,还有两个怪异的Remote接口,Home接口。也就是说 Sun 等大佬们,一开始就违背了 领域模型和OO的思想来设计 EJB 规范。 而后,又提出一些J2EE设计模式, 如DAO, Facade等推荐大家使用.

那时大家都懵懵懂懂,自然将Sun 的规范看作圣经。自然三层架构,以及 DO + DAO + BO 模式一直作为一个设计准则被大家采用。 而Spring等后来的轻量版,也没摆脱这一规程。

   所以个人认为,如果说领域模型未能成功发展,主要还是EJB规范, J2EE 服务器, Spring框架 等技术限制导致的。

   领域模型要想推广成功,没有一个像 Gavin King 这样的大师或者 某一个大厂商的技术框架,领域模型规范,App Server来支持,恐怕很难落到实处。



20 楼 狂放不羁 2008-12-01  
我觉得Dao层确实不好。虽然提供了访问数据库的接口,但是在实践中,对数据不变量的保证往往都游离与service中,所以我现在的做法就是用DDD中的repository来取代dao,但是repository与dao不同的是:repository要负责保证领域模型数据的不变量(配合一定的规则类),这样一部分的不变量保证由聚合根来完成,另外的不变量则有仓库来完成。
19 楼 taowen 2008-11-30  
wangyu4882 写道


领域模型是针对某个领域内数据和行为的封装。既然针对不同的Context。我们完全可以使用不同的领域对象
contextA.User
contextB.User
contextC.User

他们实际上对应数据库中的同一张表。
就把ContextA.B.C 当作3个完全独立的子系统。 只是需要共用数据表而已。


对,确实是这么做的。有的时候对于同一个对象,我们会用不同的包装类来包装它,附着更多的行为。但是带来的问题是“对象的身份危机”,一个对象有多个身份。这样对于使用者就造成了混乱,上下文有多个对象其实代表了同一个东西不好懂,写起来也罗嗦。
18 楼 taowen 2008-11-30  
llade 写道
DAO是从系统的角度来看问题,它面向系统,不包含领域逻辑是应该的。理想化的领域模型应该只描述领域模型之间的相互作用和相互作用的结果,结果可以是一个新的领域对象,或者原有领域对象发生了变化,这个领域对象变化通常是永久,映射到系统上就是要被存储,当需要参与下一个相互作用过程的时候被调出来。

每时每刻都有不同的领域模型被调出来发生相互作用。基于物理系统的有限性,领域模型会被做某种调适,这也是为什么领域模型经常被扭曲的原因,领域对象要穿梭与机器的不通物理系统之间(内存和硬盘,不同的主机之间),假如“保存”“传送”这些动作不存在了,现在有多少框架和模型要推翻?有时候,为了性能,领域模型需要见到这些不应该见到的东西。

JAVA最大的限制是没办法方便的mixin,没办法方便的粘贴“行为”和脱钩“行为”。而基于关系数据库的系统的最大限制是没办法随意变更你的领域模型。

Wow总结的很好。却是是这样的。qi4j对于这两个问题的解决方法是用Composite Oriented Programming来实现mixin,不过我觉得那个实现很罗嗦,不大实用。对于后者的解决办法是压根不用关系数据库做主要的存储,只用来做异步地备份和reporting,主要的存储用neo4j之类的网络数据库。最大的好处正如你所言,没有固定的schema,也就意味着多个不同版本的对象可以同时存在,也意味着不用关闭服务器就可以升级版本。
17 楼 wangyu4882 2008-11-30  
引用
在很多的讨论中,反对“充血”领域模型的同志都提到。把逻辑集中到领域模型中,会造成类的膨胀。在我个人的实践中,近千行的Entity类定义也是有的。而且这些行为往往不稳定,往往流程高度相关,复用程度并不是想象的那么高。
原因是因为,数据并没有所谓的内在行为。你不用它,它就没有行为。所以数据有什么行为,其实是使用者赋予的。而同样的数据往往会在不同的场合(context)下被使用。


领域模型是针对某个领域内数据和行为的封装。既然针对不同的Context。我们完全可以使用不同的领域对象
contextA.User
contextB.User
contextC.User

他们实际上对应数据库中的同一张表。
就把ContextA.B.C 当作3个完全独立的子系统。 只是需要共用数据表而已。
16 楼 llade 2008-11-29  
DAO是从系统的角度来看问题,它面向系统,不包含领域逻辑是应该的。理想化的领域模型应该只描述领域模型之间的相互作用和相互作用的结果,结果可以是一个新的领域对象,或者原有领域对象发生了变化,这个领域对象变化通常是永久,映射到系统上就是要被存储,当需要参与下一个相互作用过程的时候被调出来。

每时每刻都有不同的领域模型被调出来发生相互作用。基于物理系统的有限性,领域模型会被做某种调适,这也是为什么领域模型经常被扭曲的原因,领域对象要穿梭与机器的不通物理系统之间(内存和硬盘,不同的主机之间),假如“保存”“传送”这些动作不存在了,现在有多少框架和模型要推翻?有时候,为了性能,领域模型需要见到这些不应该见到的东西。

JAVA最大的限制是没办法方便的mixin,没办法方便的粘贴“行为”和脱钩“行为”。而基于关系数据库的系统的最大限制是没办法随意变更你的领域模型。
15 楼 qiuggv 2008-11-28  
现在越来觉得这些框架好像偏离了面向对象的思想,弄一大堆pojo类出来,这些pojo类和残疾人没什么区别,也怪不得叫贫血。
例如:一个person类,有名字属性,有手属性,有脚属性,却偏偏不能给他一些行为,你们说有手有脚的人,不给他干活,那和一个废人有什么区别。
偏偏要把这个人的行为要由别人去决定,例如Service层或者dao层等等,我要找张三去干个活,还得先找个中介,转来转去,真没意思。。

存属于发发牢骚。。。
14 楼 Julien 2008-11-28  
taowen 写道




这张图其实革命还没革彻底
现实开发的过程中,实际碰到的情况往往是数据本身涵盖的内容大过了Conext
我定义Conext的时候我根本不知道这个Data有多大,有多少内容,还有其他多少Conext要去管理它
不是三个饲养员一起伺候一头象,这个场景还是太理想太一厢情愿了
而是三个瞎子,这个人摸个耳朵,那个人摸个尾巴,大象本身什么样子?你永远不可能知道

所以说面向对象的“封装数据”这个思想放到现实里是很可笑的,领域模型必须彻底放弃对具体数据的独占权才是出路
我倾向于把信息世界里最终进行管理维护的核心“数据”,与代码编写中用于码砖头的“变量”彻底分割开来
这话的“数据”和“关系”单独封装组织起来,而领域模型只允许对抽象的“数据”和“关系”进行操作
而具体“数据”怎样组织,我举个例子,一个供应商系统和一个客户系统,那么同时既是供应商又是客户的对象放在哪个系统里呢?我做领域模型的时候不应该管理这个问题,我只要处理好供应商系统的逻辑,客户系统的逻辑就好,最终定义是这样:

var 系统A=客户系统.new
var 系统B=供应商系统new
var 数据C=数据集合实例.new
系统A.注入(数据C,'客户数据')
系统B.注入(数据C,'供应商数据')
数据C.列出接口
//返回:作为客户系统,方法1方法2方法3
//     作为供应商系统,方法A方法B方法C


我对将来的发展的看法,就是面向集合/面向关系的对象系统,而面向对象的集合/面向对象的关系这一套应该消亡了
这个调调的脑筋我动了很多年了,JE高手多,看看谁能搞出来
13 楼 seemoon 2008-11-28  
对象持久技术使得Dao存在的意义已经不大,因为Dao的初衷之一就是数据库sql切换的屏蔽,Dao只是一种设计模式,它是充血模型的敌人,把Dao破掉领域模型就有了,其实领域模型就是Manager+Dao的混合体,但是无论是Manager还是Dao,他们的角色都是代理,也即是说,他们是数据的控制者和操作者,而且命名方式极其“粗暴”,何为Manager?何为Dao?这些术语都是编程领域的,而不是业务模型领域的,所以除了实现技术的转变以外,领域模型在java的实现还有术语和思路的转变。同意robbin的说法。
12 楼 timerri 2008-11-28  
形而上的东西,讨论起来或许有意义,但是会有结果么?
11 楼 ray_linn 2008-11-28  
downpour 写道
第一点基本同意。不过在Java世界,有时候不得不在技术框架和使用哲学上做出balance。

第二点持保留意见,目前Dao要完全消除的可能性不大,JBoss Seam提供了范例,不过必须有容器做环境。但是我认为Dao可以是非常非常薄的一层,甚至可以不需要有实现。这一点Robbin曾经介绍过一个框架,用Annotation实现,论坛上也有人曾经用Annotation在Spring上实现过。

第三点完全同意。



消除DAO的结果 很有可能又出现Entity Bean,持久化由容器控制。
10 楼 ray_linn 2008-11-28  
PS: 有个问题是充血或者贫血模型带来的。

存储过程是平台无关的,你爱用python,用perl,用C#,用java,全部是结果一致,这种需求往往出现在核心业务里,比如BOM系统。
9 楼 yananay 2008-11-28  
我倒不觉得 DAO 是邪恶的。

我更加趋向于存在一个DAO层,或许不因该叫 DAO,应该叫 PAO(Persistence Access Object):持久访问对象的层。

因为在程序设计的早期,应该具有的概念是持久层,而不是“数据库”,数据库仅仅是持久的一个方式。

而这个层应该是面向接口的,至于实现,99%的情况应该都是数据库,但是也可能有的操作是保存到一个特殊的xml,有的操作是保存到远程的一个服务器上。即使都是数据库,也可能使用 ibatis 或者 hibernate 等不同的方式来实现。

所以大概的流程就是:

service -> domain model -> PAO (PAO 的实现就根据实际情况了)

当然,这里的 PAO 只是一个名词,沿用熟悉的称呼,叫它为 DAO 也是一样。
8 楼 downpour 2008-11-28  
robbin 写道


一、只要技术框架能够实现,尽量使用领域模型

二、无论Java还是Ruby,必须消灭DAO和TransactionScript

三、领域模型不必All-in-One,Java可以分割为 1个entity bean和几个business bean,而Ruby可以分割为1个model和几个mixin的module。




第一点基本同意。不过在Java世界,有时候不得不在技术框架和使用哲学上做出balance。

第二点持保留意见,目前Dao要完全消除的可能性不大,JBoss Seam提供了范例,不过必须有容器做环境。但是我认为Dao可以是非常非常薄的一层,甚至可以不需要有实现。这一点Robbin曾经介绍过一个框架,用Annotation实现,论坛上也有人曾经用Annotation在Spring上实现过。

第三点完全同意。
7 楼 downpour 2008-11-28  
taowen 写道

当然是可以的,只是约束数据的地方不在单单是在Domain Model上,还包括Service。别人要修改数据的时候,通不通过你的service就是职业操守的问题了。service给数据添加的约束不是强制的,而domain model可以添加强制的约束。就是这么一个问题。当然啦,你大可以说这是理论。我也说过了,贫血不贫血不是问题,适不适合自己才是问题。


我明白了,你所谈的哲学问题或者碰到的困境,还是在于程序员素质本身。而你所要解决的问题在于,如果从语法或者自然的角度就能把类似约束或者通用逻辑的问题解决,那是再好不过的事情。

我想这个初衷是没问题的。不过貌似在Java这个层面上,我们需要花费更多的代价来完成,或许借助框架,或许借助其他手段。可能有时候就需要在这些框架技术和哲学之间做出选择了。

taowen 写道

downpour 写道

这点更加是无从谈起了,为什么不写个字段,把hibernate的where用上?简单实用。事实上很多项目我们都是这么使用的。

你是指formula property吗?


formula可以做,不过要设置好lazy,否则会有性能问题。同时,一对多关联关系上也是可以设置查询条件的。
6 楼 robbin 2008-11-28  
我来说几句吧:

第一、DAO层和TransactionScript层是邪恶的!

我们在2004年一直跨度到2007年讨论来讨论去,其实都有一个隐含的前提条件:你的领域模型终究无法脱离对DAO层的依赖,以及需要TransactionScript层的包裹。而这样一来,领域模型的通用性、可移植性、业务逻辑的表达能力基本全部丧失,沦为框架限制下的奴隶。

而我们看看现在Java领域的技术进步,JPA已经普及,EJB3的隐含事务管理,甚至连Spring也可以简化成@Transactional,现在已经是我们可以去掉DAO和TransactionScript的时代了。


第二、Seam在消除了DAO层和TransactionScript以后,领域模型的感觉已经呼之欲出


这个不用多说,大家自己去看Seam文档好了。我唯一想强调的是entity bean和business bean分开有没有必要性,我的看法是有必要!这还是和Java本身语言的限制有关系:

1、Java语法表达能力有限,entity bean又不得不弄一大堆getter/setter方法,都放在一个class里面,代码的可阅读性非常差

2、business bean的很多业务逻辑方法需要容器环境,不像Rails的model可以直接mixin进来

3、Java做为目前最主流的工业语言,开发团队都是大规模编码协作的,你都放在一个class里面,团队协作会遇到很大的麻烦(事实上RoR现在也有这样的问题,但是RoR开发效率高,往往不需要那么大规模的开发团队)

3、领域模型不同类别的业务逻辑可以很容易的分到几个不同的business bean里面,这样对团队协作的好处很大。


第三、不考虑框架限制,All-in-One的领域模型好不好?


比方说RoR的model就是All-in-One的,但是一旦出现可以抽象出来,比较通用的业务逻辑,我们还是会把这些逻辑抽出来,单独实现,然后再mixin回去。


所以最终我对这个问题的总结就是:

一、只要技术框架能够实现,尽量使用领域模型

二、无论Java还是Ruby,必须消灭DAO和TransactionScript

三、领域模型不必All-in-One,Java可以分割为 1个entity bean和几个business bean,而Ruby可以分割为1个model和几个mixin的module。


相关推荐

    我国上市公司财务困境预测模型实证研究

    财务困境预测模型是财务管理领域的重要研究方向,其核心目的是通过对上市公司的财务数据进行分析,提前发现企业可能面临的财务困境风险,并给出相应的预警。财务困境又称财务危机,通常表现为公司出现严重的资产折现...

    (00-22年)财务困境-MertonDD模型

    《财务困境-MertonDD模型》是金融领域一个重要的理论模型,它主要用于评估企业违约的风险,通过对企业的市场价值和负债的分析,预测企业可能面临的财务困境。Merton模型由诺贝尔经济学奖得主罗伯特·默顿提出,是...

    博弈论中的“囚徒困境”模型1

    "囚徒困境"模型是博弈论中的一个经典案例,由Tucker在1950年提出,用于描述在非合作博弈环境下,个体最优...在实际应用中,这个模型广泛用于解释社会、经济和政治领域的许多现象,如市场竞争、环境保护和国际关系等。

    架构师特刊:联邦学习在金融领域的实践和落地困境.pdf

    因此,联邦学习既保护了数据的隐私性,又通过合作提升了模型的性能,实现了数据的隐私保护和价值利用的双重目标。 在金融领域,联邦学习的落地实践尤为关键。金融数据通常非常敏感,涉及大量个人隐私和机构机密。...

    复杂网络囚徒困境博弈matlab源程序

    在IT领域,尤其是在复杂系统建模与仿真方面,囚徒困境博弈(Prisoner's Dilemma)是一个重要的理论模型,它常被用来研究合作与背叛的行为动态。此模型结合了数学、经济学和计算机科学,而Matlab作为一种强大的数值...

    2业价值研究院-人工智能行业应对AI数据困境:恰当的数据集成方法、治理和工具.rar

    "2业价值研究院-人工智能行业应对AI数据困境:恰当的数据集成方法、治理和工具"这篇报告深入探讨了这一主题,旨在为AI从业者提供宝贵的指导。 首先,报告强调了数据集成的重要性。在AI系统中,数据是模型训练的基础...

    基于matlab实现规则网络模型囚徒困境的模拟 可以作为对演化博弈感兴趣的一个例子学习.zip.rar

    囚徒困境是博弈论中的一个经典模型,用来研究合作与背叛的决策问题。两个囚犯面临两个选择:合作(双方都沉默)或背叛(一方揭发另一方)。如果两人都合作,他们会得到较小的惩罚;如果两人都背叛,他们都会受到较大...

    练习2附件1面向电子商务的企业信息化导入模型与企业.doc

    4. **理论与应用价值**:此研究拓宽了企业信息化研究领域,从技术角度转向经济管理角度,探索如何将企业信息化与电子商务有效结合,构建理论框架和决策模型。其应用前景包括提高企业信息化投资效率,加速电子商务的...

    博弈模型.pdf

    雪堆模型与囚徒困境不同的是,遇到背叛者时合作者的收益高于双方相互背叛的收益。因此,一个人的最佳策略取决于对手的策略:如果对手选择合作,他的最佳策略是背叛;反过来,如果对手选择背叛,那么他的最佳策略是...

    财务困境与财务欺诈综述.pptx

    在识别和预防财务困境与财务欺诈方面,现代技术扮演着关键角色。数据分析和人工智能技术能帮助企业及早发现财务困境的预警信号,通过大数据分析,找出可能导致财务困境的模式和趋势。区块链技术的应用则可以提高财务...

    完美版资料集MM模型ModiglianiMillerModels米勒一莫迪利安尼模型.doc

    总之,MM模型是公司财务管理领域的一个基础理论,它揭示了资本结构与企业价值之间的关系,并在理论与实践中持续发挥着重要作用,尽管其假设可能与现实世界存在一定的差距。通过对MM模型的理解和应用,企业和管理者...

    传统Z-Score模型与人工智能视角下的财务风险预警比较.pdf

    本文档主要探讨了在财务风险预警领域,传统的“Z-Score”模型与人工智能视角下新兴的财务风险预警模型之间的比较。文中首先概述了财务风险预警的重要性,并指出了在大数据、云计算、移动技术和人工智能(大智移云)...

    论文:基于修正Jones盈余管理模型的财务危机预警研究报告报告.doc

    基于修正Jones盈余管理模型的财务危机预警研究报告主要探讨了修正Jones模型在财务危机预警领域的应用可能性及其对财务危机预警模型预测效果的影响。该研究首先引入了盈余管理理论,通过单变量分析初步证实了修正...

    财务模型和公司估值培训.pptx

    最终定价可能受到市场情况和谈判实力的影响,而投资决策则基于价值与价格的比较。 现值和贴现公式是理解公司估值的核心概念,任何资产的价值都等于其未来现金流的现值之和。这强调了现金流的重要性,因为它直接影响...

    财务模型和公司估值概述.pptx

    总的来说,财务模型和公司估值是金融领域中必不可少的工具,用于量化公司的经济价值,为投资决策提供依据。无论是投资银行还是投资管理,都需要掌握这些方法,以便做出明智的交易决策,并在复杂多变的金融市场中保持...

    奥特曼模型在公司财务预警分析中的运用共41页.pdf.zip

    当企业面临财务困境时,其负债的价值可能会降低至零,而股权价值则会受到影响。因此,通过评估企业的负债与股权之间的关系,可以估算出企业破产的可能性。 在公司财务预警分析中,奥特曼模型的应用主要体现在以下几...

    ChatGPT的应用场景与潜在价值.docx

    ChatGPT 是一个由 OpenAI 团队开发的语言模型,具有广泛的应用场景与潜在的巨大价值。本文将就 ChatGPT 的应用场景与潜在价值进行详细的讨论。 1. 客服场景:ChatGPT 模型可以通过学习大量的客户服务对话,掌握如何...

    基于作业成本法的与油价联动的第三方物流合同费用调整模型

    该模型特别针对第三方物流服务的特点,结合近年来我国成品油价格频繁上涨的现状,分析了当前物流企业在服务费用调整方面所面临的困境,并提出了解决方案。 首先,成品油价格的频繁波动对物流企业运作成本的影响极大...

    数据挖掘技术在上市公司财务困境预测中的应用.pdf

    研究发现,这些因子对于预测上市公司是否陷入财务困境具有重要价值。 在构建预测模型时,文章采用了基于极大似然估计的向前筛选策略,并通过Logistic回归分析,发现了五个重要的因子变量F1、F2、F3、F4、F5。这些...

Global site tag (gtag.js) - Google Analytics