abluedog

闲来无胜情,沽酒买一醉;闻歌知雅意,笑看是与非。

统计

常用链接

留言簿(9)

阅读排行榜

评论排行榜

PetShop is Evil?

PetShop is Evil?
抱歉使用这么耸人听闻的标题了,但是看到最近博客园上越来越多的petshop分析文章后,我觉得,有些观点实在是有些错位了。
PetShop,本来是当年MS在推.Net时,对应Java的PetStore推出的一个演示demo,这个东西本来就是演示性的,或者说很大的用处是对初学者如何快速地对平台框架了解以及基本的企业级开发概念学习——换言之,你并不应该把它当作Best Practice来指导知道开发,因为就一个真正的企业级开发模型来说,它还是不够称职,但是由于.Net开发界的重代码轻架构的风气(你看看多少讨论代码技巧组件设计的文章就知道了),它竟然成了很多.Net程序员进行架构设计的圭臬,实在是太拔高PetShop了!

在PetShop3的版本时,曾经有位来自Java界的朋友,将之重新实现了一遍,他提到了如下原因:
微软的PetShop作为标准企业应用示例中的一个已经推出了很多个版本,目前的3.2版本和以前的版本相比较,平心而论确实有了很大的提高(1.0版本无论是体系结构还是代码编写都足可以作为一个很好的反面示例,呵呵)。但是还是非常的不理想,很多.net程序员居然把它视为以面向对象方式开发的.net 应用的经典。为了纠正目前这种落后的实现方式(意识),做了这次重构,希望可以给大家做一个参考。
(找了半天,才在csdn上找到一个url:http://topic.csdn.net/t/20050204/13/3775366.html

当时博客堂的思归曾经有过评论,我把旧文翻出来,给大家参考一下:
我的看法是,微软的PetShop 3.*,除了跟Sun的J2EE版本做比较外,主要是提供了一个可做参考的样品,在当前.NET的框架,类库下,怎么手工实现分层应用。这里面涉及很多细节,怎么设计业务层/持久层,怎么做事务,业务层与持久层怎么交互,表现层怎么跟应用层交互,等等,这对初学者来说,是个很好的指导,让人了解在多层应用中,具体都需要做什么。由于O/R的差别,在大型项目中,很多时候大概会用专门的O/R Mapper或持久框架。象NHibernate这样transparent,non-intrusive的技术,指明了很好的方向。但不管用什么,多层应用里所涉及的细节都是需要了解的。在这一点上,对一个.NET开发人员而言,我想,微软的PetShop serves its purpose。
我同意,微软的PetShop要真正成为Best Practice的样板,有不少需要提高,完善的地方。譬如他们的Domain Model,用Martin Fowler的说法是有点贫血(Anemic),但这也许是因为这应用本身没有多少业务逻辑,有人指出过里面不少的缺点,也有人指出过SQL Server / Oracle的实现是否用Bridge模式来实现更恰当些。
(原文:http://blog.joycode.com/saucer/archive/2005/02/05/44160.aspx

可惜,并没有引起什么反响,就石沉大海了,在java开发界中只起个最基本演示功能的demo,在.net这边竟然被n多的程序员奉为不二法则了!

Martin Flower在2003年曾经有篇非常著名的文章:Anemic DomainModel(http://www.martinfowler.com/bliki/AnemicDomainModel.html
他的观点是:象PetShop里面的OrderItem这样的Domain Model类,仅包含属性(getter/setter),而不包含任何领域逻辑,而统统有一个ServiceLayer或者说一个ManagerLayer来进行管理,这实在是一种anti-pattern。(详细的原因大家还是啃啃e文吧)
而前些年在Java界Anemic Domain Model的流行,很大程度上是因为EJB2.0的不良设计以及DAO模式的滥觞。
关于DAO模式,请参考:http://java.sun.com/blueprints/corej2eepatterns/Patterns/DataAccessObject.html


企业级架构的设计,本来就是争论比较多,但是经过这几年的争论,目前对Anemic DomainModel已经基本上取得了共识,而现在几种比较流行的
层次划分法,大家比较有共识的有如下几种(我从javaeye拿来,由robbin总结的,做些代码性的调整):
1.失血模型
失血模型简单来说,就是domain object只有属性的getter/setter方法的纯数据类,所有的业务逻辑完全由business object来完成(又称TransactionScript),这种模型下的domain object被Martin Fowler称之为“贫血的domain object”。

2.”贫血模型“(注意:这个贫血模型在javaeye上讨论n久之后已经与Martin Flower的贫血模型有所差别,他所指的”贫血“被称为”失血“了。
domain object包含了不依赖于持久化的领域逻辑,而那些依赖持久化的领域逻辑被分离到Service层。
Service(业务逻辑,事务封装) --> DAO ---> domain object(Item)
这也就是Martin Fowler指的rich domain object
1.一个带有业务逻辑的实体类,即domain object是Item
2.一个DAO接口ItemDao
3.一个DAO实现ItemDaoSQLServerImpl(属于DAL层)
4.一个业务逻辑对象ItemManager(调用ItemDao)
这种模型的优点:
1、各层单向依赖,结构清楚,易于实现和维护
2、设计简单易行,底层模型非常稳定
这种模型的缺点:
1、domain object的部分比较紧密依赖的持久化domain logic被分离到Service层,显得不够OO
2、Service层过于厚重


3.充血模型
充血模型和第二种模型差不多,所不同的就是如何划分业务逻辑,即认为,绝大多业务逻辑都应该被放在domain object里面(包括持久化逻辑),而Service层应该是很薄的一层,仅仅封装事务和少量逻辑,不和DAO层打交道。
Service(事务封装) ---> domain object <---> DAO
这种模型就是把第二种模型的domain object和business object合二为一了。所以ItemManager就不需要了,在这种模型下面,只有三个类,他们分别是:
Item:包含了实体类信息,也包含了所有的业务逻辑
ItemDao:持久化DAO接口类
ItemDaoSQLServerImpl:DAO接口的实现类

在这种模型中,所有的业务逻辑全部都在Item中,事务管理也在Item中实现。
这种模型的优点:
1、更加符合OO的原则
2、Service层很薄,只充当Facade的角色,不和DAO打交道。
这种模型的缺点:
1、DAO和domain object形成了双向依赖,复杂的双向依赖会导致很多潜在的问题。
2、如何划分Service层逻辑和domain层逻辑是非常含混的,在实际项目中,由于设计和开发人员的水平差异,可能导致整个结构的混乱无序。
3、考虑到Service层的事务封装特性,Service层必须对所有的domain object的逻辑提供相应的事务封装方法,
其结果就是Service完全重定义一遍所有的domain logic,非常烦琐,而且Service的事务化封装其意义就等于把OO的domain logic转换为过程的Service TransactionScript。该充血模型辛辛苦苦在domain层实现的OO在Service层又变成了过程式,对于Web层程序员的角度来看,和贫血模型没有什么区别了。

4.胀血模型
基于充血模型的第三个缺点,有同学提出,干脆取消Service层,只剩下domain object和DAO两层,在domain object的domain logic上面封装事务。
domain object(事务封装,业务逻辑) <---> DAO
似乎ruby on rails就是这种模型,他甚至把domain object和DAO都合并了。
该模型优点:
1、简化了分层
2、也算符合OO
该模型缺点:
1、很多不是domain logic的service逻辑也被强行放入domain object ,引起了domain ojbect模型的不稳定
2、domain object暴露给web层过多的信息,可能引起意想不到的副作用。

robbin在后面曾经有个总结,我摘抄如下:
简单评价一下:
第一种模型绝大多数人都反对,因此反对理由我也不多讲了。但遗憾的是,我观察到的实际情形是,很多使用Hibernate的公司最后都是这种模型,这里面有很大的原因是很多公司的技术水平没有达到这种层次,所以导致了这种贫血模型的出现。从这一点来说,Martin Fowler的批评声音不是太响了,而是太弱了,还需要再继续呐喊。
第二种模型就是Martin Fowler一直主张的模型,实际上也是我一直在实际项目中采用这种模型。我没有看过Martin的POEAA,之所以能够自己摸索到这种模型,也是因为从02年我已经开始思考这个问题并且寻求解决方案了,但是当时没有看到Hibernate,那时候做的一个小型项目我已经按照这种模型来做了,但是由于没有O/R Mapping的支持,写到后来又不得不全部改成贫血的domain object,项目做完以后再继续找,随后就发现了Hibernate。当然,现在很多人一开始就是用Hibernate做项目,没有经历过我经历的那个阶段。
不过我觉得这种模型仍然不够完美,因为你还是需要一个业务逻辑层来封装所有的domain logic,这显得非常罗嗦,并且业务逻辑对象的接口也不够稳定。如果不考虑业务逻辑对象的重用性的话(业务逻辑对象的可重用性也不可能好),很多人干脆就去掉了xxxManager这一层,在Web层的Action代码直接调用xxxDao,同时容器事务管理配置到Action这一层上来。Hibernate的caveatemptor就是这样架构的一个典型应用。
第三种模型是我很反对的一种模型,这种模型下面,Domain Object和DAO形成了双向依赖关系,无法脱离框架测试,并且业务逻辑层的服务也和持久层对象的状态耦合到了一起,会造成程序的高度的复杂性,很差的灵活性和糟糕的可维护性。也许将来技术进步导致的O/R Mapping管理下的domain object发展到足够的动态持久透明化的话,这种模型才会成为一个理想的选择。就像O/R Mapping的流行使得第二种模型成为了可能.

javaeye的这篇原文在:http://forum.javaeye.com/viewtopic.php?t=17579
如果你对java以及hibernate比较了解的话,我建议你不妨关注一下。

我的观点:
PetShop就用来学习吧,仅此而已。
当然,毕竟架构的设计需要考虑团队的整体水平,在整体水平参差不齐的情况下,而且项目比较小,PetShop的结构也不妨拿来使用,毕竟,我们是做项目,而不是做研究,这是本着实际开发的状况来说的,但是如果是学习并想提高的话,还是——了解并忘记。

posted on 2006-04-22 21:57 abluedog 阅读(3506) 评论(24)  编辑 收藏 所属分类: .Net

评论

#1楼  2006-04-22 22:22 Dflying Chen      

同感,现在cnblogs里面都是PetShop,看得恶心(恕我用这个词)死了…………   回复  引用  查看    

#2楼  2006-04-22 22:47 idior      

没有必要这么惊讶,更用不着恶心.
现在cnblogs关注petshop,很大一部分原因是因为petshop4的推出.
petshop4用来学习.net的新技术还是不错的例子, 何况cnblogs里的文章质量比较高, 看看大家对它的分析挺好.
本来就不该把它当最佳实践,明白这个道理就行了.就当它是学技术的教程.

我的评价就是 petshop is just a pet   回复  引用  查看    

#3楼  2006-04-23 00:06 梁广永      

指导性的理论

灵活的实际
的问题。   回复  引用  查看    

#4楼  2006-04-23 00:07 梁广永      

老问题,   回复  引用  查看    

#5楼  2006-04-23 02:29 卡卡.net      

petshop给初学者架构分层的概念,真正的企业级应用接触倒是很少,希望有人能够提供一个非常简单的实现.以及Enterprise Library,NHibernate在里面的具体应用.   回复  引用  查看    

#6楼  2006-04-23 09:22 jjx [未注册用户]

什么胀血、失血之类的名词也很恶心,大家千万不要被那些所谓的咨询师所左右。
真正的开发者应该追求无我的最高境界,怎么方便怎么来,一切从实际出发
  回复  引用    

#7楼  2006-04-23 09:55 wt [未注册用户]

非常同意楼主的观点,PetShop对于.net和分层架构的初学则来说,确实是个好东西。并且容易上手,但是走过那个阶段后,构架更加复杂的应用就不是PetShop能够指导的了。   回复  引用    

#8楼  2006-04-23 12:22 Zhongkeruanjian      

这种情况的出现有几方面的原因:

1 MS的过于强势:在MS的NET应用世界里,MS主要推崇的是数据集网关模式(TableGateWay)比如它的DataSet。在这种模式下,Domain Object不贫血都不行。而NET下的程序员大多数都以MS为标准。认为这种模式是天经地义的,没有勇气和信心去探索其他模式。而是把自己禁锢在NET的小圈子里。
2 现在NET下的应用,特别是国内的NET应用,大多数还是属于中,小型应用。这种应用的特点是开发速度快,系统不需要大多的维护和扩展(简单系统之所以简单,多半在于其需求能一次性确定,不会随着时间的变化而有太多的变化)。这种系统的构架用数据集网关模式和实体的贫血模型会来得更自然,开发速度也更快。而领域模式在这种系统中的实现会相对来讲比较复杂。而在JAVA世界里。大型的企业级应用比较多,这种应用的最大的特点就是业务逻辑复杂,需求变化快。这样JAVAR就不得不思考,用什么样的构架才能把让系统能“生态平衡”和拥抱变化。
3 NET程序员的固步自封。在JAVA社区里,这种构架的问题域被广泛讨论。比如Javayeye的那个关于DOMAIN OBJECT模式的讨论。但在NET社区里。基本上没有这样的讨论。大家都被那些具体的技术细节所掩盖。只有极少数的有识之士在呐喊。比如楼主。但是这种声音太小,太脆弱了。   回复  引用  查看    

#9楼  2006-04-23 14:14 Walkdan      

Petshop仅仅是个Sample,初学者应该了解,而不能模仿。即使到了PetShop4,结构性也很不理想。个人觉得会给初学者很多误导。另外一个误导就是MS Enterprise Library。

不过我也不太同意采用过多的Java/Domain术语来描述.NET,.NET对世界的认识也有自己独特的地方。

MS一向都是后发制人,我看好DLINQ,相信到了Petshop5(6?)会有根本的改变。   回复  引用  查看    

#10楼  2006-04-23 16:21 jinx [未注册用户]

楼主不要废话了,用实际的行动来证明。。
初学者没什么项目入门,看petshop也有错? 要不你写一个入门级的Enterprise Project

  回复  引用    

#11楼  2006-04-23 19:47 卡卡.net      

Walkdan
解释一下"另外一个误导就是MS Enterprise Library。".   回复  引用  查看    

#12楼  2006-04-23 22:04 xuexi [未注册用户]

robbin的那两个帖子,我从头到尾,确实部分内容是由道理的,但我关注的是如何实现,实现起来能应付复杂多变的逻辑,实现起来是否过于复杂,每种模型实现时需要什么样的基础支持或必备支持,在.net下是否有更好的思路等等。   回复  引用    

#13楼  2006-04-23 22:16 xuexi [未注册用户]

robbin的那两个帖子,我从头到尾一直关注着,确实部分内容是由道理的,但我关注的是如何实现,实现起来能应付复杂多变的逻辑,实现起来是否过于复杂,每种模型实现时需要什么样的基础支持或必备支持,在.net下是否有更好的思路等等。   回复  引用    

#14楼  2006-04-23 23:19 Walkdan      

@卡卡.net
Enterprise Library至多只能叫"Enterprise Helper"或"Enterprise Utility",或勉强叫"Low Level Enterprise Library"。里面的Enterprise这个单词会误导很多人。

另外,个人认为Enterprise Lib是过度设计的典范。   回复  引用  查看    

#15楼  2006-04-24 09:21 Nomagic      

petshop4我只用来学习一下.net2.0的一些新特征。至于程序架构方面,我对petshop包括duwamish都非常的不认同,在我看来他们都是面向过程的软件开发。   回复  引用  查看    

#16楼  2006-04-24 10:13 Terrylee      

我也说两句
1.我不太认同Dflying Chen 用“恶心”这个词,这根本没什么恶心的,PetShop4.0的出现一定有它的理由,不管它是一个Example也好,还是Demo也行,Petshop4.0也有它可取得地方,它里面用的设计模式等思想,对于初学者来说,未尝不是一个很好的入门教程。

2.我也同意楼主的观点,.NET社区对于架构各方面的讨论的确比较少,不像Java。重代码轻架构早就存在了,这一点相信从很多文章的阅读量上就可以反映出来,很多编码小技巧仅仅使系统徒具形而无神,对于系统的神上我们还得去努力!

以上仅为个人观点:-)   回复  引用  查看    

#17楼  2006-04-24 21:35 爱 [未注册用户]

无所谓好与坏,优秀有优秀的好处,差劲有差劲的好处,没有坏的架构哪里来的优良的架构?
不了解孬的,怎么知道那是好的?不分好坏都需要学习与了解的。

做项目与做产品又有所不同的,,懒得说了
  回复  引用    

#18楼  2006-06-29 16:04 xc#      

过了   回复  引用  查看    

#19楼  2006-09-23 07:10 BigDaddy [未注册用户]

失血,贫血,充血,胀血, 我。。。。靠
现在一看全是拾人牙慧的东西...什么IOC,DI,“don't call me, I call u". 什么是模式?
模式就是三点灵魂:
1。不用recompile可以应付run time的变化。
2。好维护,好扩展
3。逻辑美,简单

咋好用,咋来,搞那么多名词,啥也不能说明。   回复  引用    

#20楼  2006-10-31 00:01 gma [未注册用户]

一套一套的.
楼主本事.写个出来和MS比比   回复  引用    

#21楼  2007-04-27 10:56 非寒 [未注册用户]

LS言重了···
1 Petshop没你说的那么无用,他的出现肯定是有他的道理
2 请你 不要拿java里面的名词来规划.net

突然发现你下面的 “X血模式” 都是我学习阶段的“混乱模式”

相反,我倒觉得petshop让我思路更清晰   回复  引用    

#22楼  2007-10-08 17:11 匿名 [未注册用户]

对于你认为好的东西我们应该写出来让大家评论一下到底好不好,也给学习者提供参考;
对于不好的东西也写出来,它到底如何不好,而且你最好写出来如何改正,如何提高,如何设计架构才更好,也给学习者提供参考;

我相信PETSHOP4出来以前楼主肯定是写不出PETSHOP4这样的代码的,否则,你也不会在这里谈天论地了,早就让比尔盖茨请走了,或者你直接把微软收购了吧,要不你也写一个WPSOFFICE来和微软的MSOFFICE抗衡一下,那才叫牛!

让我们共同提高,请不要妄自菲薄,更请楼主不要用一些XX语言来污染程序员的氛围!   回复  引用    

#23楼  2007-10-09 21:27 郭付阳      

感谢楼主的呐喊和用心,最近好少有时间阅读这类文章与学术上的讨论,先收藏一下作为参考。   回复  引用  查看    

#24楼  2007-11-02 13:58 赵秋仙 [未注册用户]

这篇文章精辟,真是说得很透彻,对那些架构分析的很到。   回复  引用    


标题  
姓名  
主页
Email (博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
该文被作者在 2006-04-22 22:25 编辑过


相关链接: