Grey Sand

学习与积累

  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 :: 管理 ::

旧文章了,纯粹拿来收藏,原文来自cnblog,作者AblueDog

以下为转载:
抱歉使用这么耸人听闻的标题了,但是看到最近博客园上越来越多的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 2007-09-20 16:12  leon1005  阅读(356)  评论(1)    收藏  举报