收藏 分享(赏)

失血模型,贫血模型,充血模型,胀血模型.doc

上传人:hskm5268 文档编号:7586549 上传时间:2019-05-21 格式:DOC 页数:16 大小:60KB
下载 相关 举报
失血模型,贫血模型,充血模型,胀血模型.doc_第1页
第1页 / 共16页
失血模型,贫血模型,充血模型,胀血模型.doc_第2页
第2页 / 共16页
失血模型,贫血模型,充血模型,胀血模型.doc_第3页
第3页 / 共16页
失血模型,贫血模型,充血模型,胀血模型.doc_第4页
第4页 / 共16页
失血模型,贫血模型,充血模型,胀血模型.doc_第5页
第5页 / 共16页
点击查看更多>>
资源描述

1、一、失血模型失血模型简单来说,就是 domain object只有属性的 getter/setter方法的纯数据类,所有的业务逻辑完全由 business object来完成(又称TransactionScript),这种模型下的 domain object被 Martin Fowler称之为“贫血的domain object”。下面用举一个具体的代码来说明,代码来自 Hibernate的 caveatemptor,但经过我的改写:一个实体类叫做 Item,指的是一个拍卖项目一个 DAO接口类叫做 ItemDao一个 DAO接口实现类叫做 ItemDaoHibernateImpl一个业务逻辑类

2、叫做 ItemManager(或者叫做 ItemService)java代码: public class Item implements Serializable private Long id = null;private int version;private String name;private User seller;private String description;private MonetaryAmount initialPrice;private MonetaryAmount reservePrice;private Date startDate;private Date

3、endDate;private Set categorizedItems = new HashSet();private Collection bids = new ArrayList();private Bid successfulBid;private ItemState state;private User approvedBy;private Date approvalDatetime;private Date created = new Date();/ getter/setter方法省略不写,避免篇幅太长java代码: public interface ItemDao public

4、 Item getItemById(Long id);public Collection findAll();public void updateItem(Item item);ItemDao定义持久化操作的接口,用于隔离持久化代码。java代码: public class ItemDaoHibernateImpl implements ItemDao extends HibernateDaoSupport public Item getItemById(Long id) return (Item) getHibernateTemplate().load(Item.class, id);pub

5、lic Collection findAll() return (List) getHibernateTemplate().find(“from Item“);public void updateItem(Item item) getHibernateTemplate().update(item);ItemDaoHibernateImpl完成具体的持久化工作,请注意,数据库资源的获取和释放是在ItemDaoHibernateImpl里面处理的,每个 DAO方法调用之前打开 Session,DAO 方法调用之后,关闭 Session。(Session 放在 ThreadLocal中,保证一次调用

6、只打开关闭一次)java代码: public class ItemManager private ItemDao itemDao;public void setItemDao(ItemDao itemDao) this.itemDao = itemDao;public Bid loadItemById(Long id) itemDao.loadItemById(id);public Collection listAllItems() return itemDao.findAll();public Bid placeBid(Item item, User bidder, MonetaryAmou

7、nt bidAmount,Bid currentMaxBid, Bid currentMinBid) throws BusinessException if (currentMaxBid != null / Auction is activeif ( !state.equals(ItemState.ACTIVE) )throw new BusinessException(“Auction is not active yet.“);/ Auction still validif ( item.getEndDate().before( new Date() ) )throw new Busines

8、sException(“Cant place new bid, auction already ended.“);/ Create new BidBid newBid = new Bid(bidAmount, item, bidder);/ Place bid for this Itemitem.getBids().add(newBid);itemDao.update(item); / 调用 DAO完成持久化操作return newBid;事务的管理是在 ItemManger这一层完成的,ItemManager 实现具体的业务逻辑。除了常见的和 CRUD有关的简单逻辑之外,这里还有一个 pla

9、ceBid的逻辑,即项目的竞标。以上是一个完整的第一种模型的示例代码。在这个示例中,placeBid,loadItemById,findAll 等等业务逻辑统统放在 ItemManager中实现,而Item只有 getter/setter方法。二、贫血模型简单来说,就是 domain ojbect包含了不依赖于持久化的领域逻辑,而那些依赖持久化的领域逻辑被分离到 Service层。Service(业务逻辑,事务封装) DAO - domain object这也就是 Martin Fowler指的 rich domain object一个带有业务逻辑的实体类,即 domain object是 I

10、tem一个 DAO接口 ItemDao一个 DAO实现 ItemDaoHibernateImpl一个业务逻辑对象 ItemManagerjava代码: public class Item implements Serializable / 所有的属性和 getter/setter方法同上,省略public Bid placeBid(User bidder, MonetaryAmount bidAmount,Bid currentMaxBid, Bid currentMinBid)throws BusinessException / Check highest bid (can also be

11、a different Strategy (pattern)if (currentMaxBid != null / Auction is activeif ( !state.equals(ItemState.ACTIVE) )throw new BusinessException(“Auction is not active yet.“);/ Auction still validif ( this.getEndDate().before( new Date() ) )throw new BusinessException(“Cant place new bid, auction alread

12、y ended.“);/ Create new BidBid newBid = new Bid(bidAmount, this, bidder);/ Place bid for this Itemthis.getBids.add(newBid); / 请注意这一句,透明的进行了持久化,但是不能在这里调用 ItemDao,Item 不能对 ItemDao产生依赖!return newBid;竞标这个业务逻辑被放入到 Item中来。请注意 this.getBids.add(newBid); 如果没有Hibernate或者 JDO这种 O/R Mapping的支持,我们是无法实现这种透明的持久化行为

13、的。但是请注意,Item 里面不能去调用 ItemDAO,对 ItemDAO产生依赖!ItemDao和 ItemDaoHibernateImpl的代码同上,省略。java代码: public class ItemManager private ItemDao itemDao;public void setItemDao(ItemDao itemDao) this.itemDao = itemDao;public Bid loadItemById(Long id) itemDao.loadItemById(id);public Collection listAllItems() return i

14、temDao.findAll();public Bid placeBid(Item item, User bidder, MonetaryAmount bidAmount,Bid currentMaxBid, Bid currentMinBid) throws BusinessException item.placeBid(bidder, bidAmount, currentMaxBid, currentMinBid);itemDao.update(item); / 必须显式的调用 DAO,保持持久化在第二种模型中,placeBid 业务逻辑是放在 Item中实现的,而 loadItemByI

15、d和 findAll业务逻辑是放在 ItemManager中实现的。不过值得注意的是,即使 placeBid业务逻辑放在 Item中,你仍然需要在 ItemManager中简单的封装一层,以保证对 placeBid业务逻辑进行事务的管理和持久化的触发。这种模型是 Martin Fowler所指的真正的 domain model。在这种模型中,有三个业务逻辑方法:placeBid,loadItemById 和 findAll,现在的问题是哪个逻辑应该放在 Item中,哪个逻辑应该放在 ItemManager中。在我们这个例子中,placeBid放在 Item中(但是 ItemManager也需要

16、对它进行简单的封装),loadItemById 和 findAll是放在 ItemManager中的。切分的原则是什么呢? Rod Johnson提出原则是“case by case”,可重用度高的,和domain object状态密切关联的放在 Item中,可重用度低的,和 domain object状态没有密切关联的放在 ItemManager中。经过上面的讨论,如何区分 domain logic和 business logic,我想提出一个改进的区分原则:domain logic只应该和这一个 domain object的实例状态有关,而不应该和一批 domain object的状态有关

17、;当你把一个 logic放到 domain object中以后,这个 domain object应该仍然独立于持久层框架之外(Hibernate,JDO),这个 domain object仍然可以脱离持久层框架进行单元测试,这个 domain object仍然是一个完备的,自包含的,不依赖于外部环境的领域对象,这种情况下,这个 logic才是 domain logic。这里有一个很确定的原则:logic 是否只和这个 object的状态有关,如果只和这个 object有关,就是 domain logic;如果 logic是和一批 domainobject的状态有关,就不是 domain log

18、ic,而是 business logic。Item的 placeBid这个业务逻辑方法没有显式的对持久化 ItemDao接口产生依赖,所以要放在 Item中。请注意,如果脱离了 Hibernate这个持久化框架,Item 这个 domain object是可以进行单元测试的,他不依赖于 Hibernate的持久化机制。它是一个独立的,可移植的,完整的,自包含的域对象。而 loadItemById和 findAll这两个业务逻辑方法是必须显式的对持久化 ItemDao接口产生依赖,否则这个业务逻辑就无法完成。如果你要把这两个方法放在 Item中,那么 Item就无法脱离 Hibernate框架,

19、无法在 Hibernate框架之外独立存在。这种模型的优点:1、各层单向依赖,结构清楚,易于实现和维护2、设计简单易行,底层模型非常稳定这种模型的缺点:1、domain object的部分比较紧密依赖的持久化 domain logic被分离到 Service层,显得不够 OO2、Service 层过于厚重三、充血模型充血模型和第二种模型差不多,所不同的就是如何划分业务逻辑,即认为,绝大多业务逻辑都应该被放在 domain object里面(包括持久化逻辑),而 Service层应该是很薄的一层,仅仅封装事务和少量逻辑,不和 DAO层打交道。Service(事务封装) - domain obje

20、ct DAO这种模型就是把第二种模型的 domain object和 business object合二为一了。所以ItemManager就不需要了,在这种模型下面,只有三个类,他们分别是:Item:包含了实体类信息,也包含了所有的业务逻辑ItemDao:持久化 DAO接口类ItemDaoHibernateImpl:DAO 接口的实现类由于 ItemDao和 ItemDaoHibernateImpl和上面完全相同,就省略了。java代码: public class Item implements Serializable / 所有的属性和 getter/setter方法都省略private s

21、tatic ItemDao itemDao;public void setItemDao(ItemDao itemDao) this.itemDao = itemDao;public static Item loadItemById(Long id) return (Item) itemDao.loadItemById(id);public static Collection findAll() return (List) itemDao.findAll();public Bid placeBid(User bidder, MonetaryAmount bidAmount,Bid curren

22、tMaxBid, Bid currentMinBid)throws BusinessException / Check highest bid (can also be a different Strategy (pattern)if (currentMaxBid != null / Auction is activeif ( !state.equals(ItemState.ACTIVE) )throw new BusinessException(“Auction is not active yet.“);/ Auction still validif ( this.getEndDate().

23、before( new Date() ) )throw new BusinessException(“Cant place new bid, auction already ended.“);/ Create new BidBid newBid = new Bid(bidAmount, this, bidder);/ Place bid for this Itemthis.addBid(newBid);itemDao.update(this); / 调用 DAO进行显式持久化return newBid;在这种模型中,所有的业务逻辑全部都在 Item中,事务管理也在 Item中实现。这种模型的优

24、点:1、更加符合 OO的原则2、Service 层很薄,只充当 Facade的角色,不和 DAO打交道。这种模型的缺点:1、DAO 和 domain object形成了双向依赖,复杂的双向依赖会导致很多潜在的问题。2、如何划分 Service层逻辑和 domain层逻辑是非常含混的,在实际项目中,由于设计和开发人员的水平差异,可能导致整个结构的混乱无序。3、考虑到 Service层的事务封装特性,Service 层必须对所有的 domain object的逻辑提供相应的事务封装方法,其结果就是 Service完全重定义一遍所有的 domain logic,非常烦琐,而且 Service的事务化

25、封装其意义就等于把 OO的domain logic转换为过程的 Service TransactionScript。该充血模型辛辛苦苦在 domain层实现的 OO在 Service层又变成了过程式,对于 Web层程序员的角度来看,和贫血模型没有什么区别了。1.事务我是不希望由 Item管理的,而是由容器或更高一层的业务类来管理。2.如果 Item不脱离持久层的管理,如 JDO的 pm,那么 itemDao.update(this); 是不需要的,也就是说 Item是在事务过程中从数据库拿出来的,并且声明周期不超出当前事务的范围。3.如果 Item是脱离持久层,也就是在 Item的生命周期超出

26、了事务的范围,那就要必须显示调用 update或 attach之类的持久化方法的,这种时候就应该是按 robbin所说的第 2种模型来做。四、胀血模型基于充血模型的第三个缺点,有同学提出,干脆取消 Service层,只剩下 domain object和 DAO两层,在 domain object的 domain logic上面封装事务。domain object(事务封装,业务逻辑) DAO似乎 ruby on rails就是这种模型,他甚至把 domain object和 DAO都合并了。该模型优点:1、简化了分层2、也算符合 OO该模型缺点:1、很多不是 domain logic的 ser

27、vice逻辑也被强行放入 domain object ,引起了 domain ojbect模型的不稳定2、domain object 暴露给 web层过多的信息,可能引起意想不到的副作用。评价:在这四种模型当中,失血模型和胀血模型应该是不被提倡的。而贫血模型和充血模型从技术上来说,都已经是可行的了。但是我个人仍然主张使用贫血模型。其理由:1、参考充血模型第三个缺点,由于暴露给 web层程序拿到的还是 Service Transaction Script,对于 web层程序员来说,底层 OO意义丧失了。2、参考充血模型第三个缺点,为了事务封装,Service 层要给每个 domain logic

28、提供一个过程化封装,这对于编程来说,做了多余的工作,非常烦琐。3、domain object和 DAO的双向依赖在做大项目中,考虑到团队成员的水平差异,很容易引入不可预知的潜在 bug。4、如何划分 domain logic和 service logic的标准是不确定的,往往要根据个人经验,有些人就是觉得某个业务他更加贴近 domain,也有人认为这个业务是贴近 service的。由于划分标准的不确定性,带来的后果就是实际项目中会产生很多这样的争议和纠纷,不同的人会有不同的划分方法,最后就会造成整个项目的逻辑分层混乱。这不像贫血模型中我提出的按照是否依赖持久化进行划分,这种标准是非常确定的,不

29、会引起争议,因此团队开发中,不会产生此类问题。5、贫血模型的 domain object确实不够 rich,但是我们是做项目,不是做研究,好用就行了,管它是不是那么纯的 OO呢?其实我不同意firebody认为的贫血模型在设计模型和实现代码中有很大跨越的说法。一个设计模型到实现的时候,你直接得到两个类:一个实体类,一个控制类就行了,没有什么跨越。简单评价一下:第一种模型绝大多数人都反对,因此反对理由我也不多讲了。但遗憾的是,我观察到的实际情形是,很多使用 Hibernate的公司最后都是这种模型,这里面有很大的原因是很多公司的技术水平没有达到这种层次,所以导致了这种贫血模型的出现。从这一点来说

30、,Martin Fowler 的批评声音不是太响了,而是太弱了,还需要再继续呐喊。第二种模型就是 Martin Fowler一直主张的模型,实际上也是我一直在实际项目中采用这种模型。我没有看过 Martin的 POEAA,之所以能够自己摸索到这种模型,也是因为从 02年我已经开始思考这个问题并且寻求解决方案了,但是当时没有看到 Hibernate,那时候做的一个小型项目我已经按照这种模型来做了,但是由于没有 O/R Mapping的支持,写到后来又不得不全部改成贫血的 domain object,项目做完以后再继续找,随后就发现了 Hibernate。当然,现在很多人一开始就是用 Hibern

31、ate做项目,没有经历过我经历的那个阶段。不过我觉得这种模型仍然不够完美,因为你还是需要一个业务逻辑层来封装所有的 domain logic,这显得非常罗嗦,并且业务逻辑对象的接口也不够稳定。如果不考虑业务逻辑对象的重用性的话(业务逻辑对象的可重用性也不可能好),很多人干脆就去掉了 xxxManager这一层,在 Web层的 Action代码直接调用 xxxDao,同时容器事务管理配置到 Action这一层上来。Hibernate的 caveatemptor就是这样架构的一个典型应用。第三种模型是我很反对的一种模型,这种模型下面,Domain Object和 DAO形成了双向依赖关系,无法脱离

32、框架测试,并且业务逻辑层的服务也和持久层对象的状态耦合到了一起,会造成程序的高度的复杂性,很差的灵活性和糟糕的可维护性。也许将来技术进步导致的 O/R Mapping管理下的 domain object发展到足够的动态持久透明化的话,这种模型才会成为一个理想的选择。就像 O/R Mapping的流行使得第二种模型成为了可能Martin Fowler的 Domain Model,或者说我们的第二种模型难道是完美无缺的吗?当然不是,接下来我就要分析一下它的不足,以及可能的解决办法,而这些都来源于我个人的实践探索。在第二种模型中,我们可以清楚的把这 4个类分为三层:1、实体类层,即 Item,带有

33、domain logic的 domain object2、DAO 层,即 ItemDao和 ItemDaoHibernateImpl,抽象持久化操作的接口和实现类3、业务逻辑层,即 ItemManager,接受容器事务控制,向 Web层提供统一的服务调用在这三层中我们大家可以看到,domain object和 DAO都是非常稳定的层,其实原因也很简单,因为 domain object是映射数据库字段的,数据库字段不会频繁变动,所以 domain object也相对稳定,而面向数据库持久化编程的 DAO层也不过就是 CRUD而已,不会有更多的花样,所以也很稳定。问题就在于这个充当 busines

34、s workflow facade的业务逻辑对象,它的变动是相当频繁的。业务逻辑对象通常都是无状态的、受事务控制的、Singleton类,我们可以考察一下业务逻辑对象都有哪几类业务逻辑方法:第一类:DAO 接口方法的代理,就是上面例子中的 loadItemById方法和 findAll方法。ItemManager之所以要代理这种类,目的有两个:向 Web层提供统一的服务调用入口点和给持久化方法增加事务控制功能。这两点都很容易理解,你不能既给 Web层程序员提供 xxxManager,也给他提供 xxxDao,所以你需要用xxxManager封装 xxxDao,在这里,充当了一个简单代理功能;而

35、事务控制也是持久化方法必须的,事务可能需要跨越多个 DAO方法调用,所以必须放在业务逻辑层,而不能放在 DAO层。但是必须看到,对于一个典型的 web应用来说,绝大多数的业务逻辑都是简单的 CRUD逻辑,所以这种情况下,针对每个 DAO方法,xxxManager 都需要提供一个对应的封装方法,这不但是非常枯燥的,也是令人感觉非常不好的。第二类:domain logic的方法代理。就是上面例子中 placeBid方法。虽然 Item已经有了placeBid方法,但是 ItemManager仍然需要封装一下 Item的 placeBid,然后再提供一个简单封装之后的代理方法。这和第一种情况类似,其

36、原因也一样,也是为了给 Web层提供一个统一的服务调用入口点和给隐式的持久化动作提供事务控制。同样,和第一种情况一样,针对每个 domain logic方法,xxxManager 都需要提供一个对应的封装方法,同样是枯燥的,令人不爽的。第三类:需要多个 domain object和 DAO参与协作的 business workflow。这种情况是业务逻辑对象真正应该完成的职责。在这个简单的例子中,没有涉及到这种情况,不过大家都可以想像的出来这种应用场景,因此不必举例说明了。通过上面的分析可以看出,只有第三类业务逻辑方法才是业务逻辑对象真正应该承担的职责,而前两类业务逻辑方法都是“无奈之举” ,

37、不得不为之的事情,不但枯燥,而且令人沮丧。分析完了业务逻辑对象,我们再回头看一下 domain object,我们要仔细考察一下 domain logic的话,会发现 domain logic也分为两类:第一类:需要持久层框架隐式的实现透明持久化的 domain logic,例如 Item的 placeBid方法中的这一句:java代码: this.getBids().add(newBid);上面已经着重提到,虽然这仅仅只是一个 Java集合的添加新元素的操作,但是实际上通过事务的控制,会潜在的触发两条 SQL:一条是 insert一条记录到 bid表,一条是更新 item表相应的记录。如果我

38、们让 Item脱离 Hibernate进行单元测试,它就是一个单纯的 Java集合操作,如果我们把他加入到 Hibernate框架中,他就会潜在的触发两条 SQL,这就是隐式的依赖于持久化的domain logic。特别请注意的一点是:在没有 Hibernate/JDO这类可以实现“透明的持久化”工具出现之前,这类 domain logic是无法实现的。对于这一类 domain logic,业务逻辑对象必须提供相应的封装方法,以实现事务控制。第二类:完全不依赖持久化的 domain logic,例如 readonly例子中的 Topic,如下:java代码: class Topic boole

39、an isAllowReply() Calendar dueDate = Calendar.getInstance();dueDate.setTime(lastUpdatedTime);dueDate.add(Calendar.DATE, forum.timeToLive);Date now = new Date();return now.after(dueDate.getTime();注意这个 isAllowReply方法,他和持久化完全不发生一丁点关系。在实际的开发中,我们同样会遇到很多这种不需要持久化的业务逻辑(主要发生在日期运算、数值运算和枚举运算方面),这种 domain logic

40、不管脱离不脱离所在的框架,它的行为都是一致的。对于这种 domain logic,业务逻辑层并不需要提供封装方法,它可以适用于任何场合。概括说:action 做为控制器 ,service 面向 use case,domain object 是中间稳定的一层,dao是作为下层的服务,提供持久化服务,可以被domain object所使用。针对上面帖子中分析的业务逻辑对象的方法有三类的情况,我们在实际的项目中会遇到一些困扰。主要的困扰就是业务逻辑对象的方法会变动的相当频繁,并且业务逻辑对象的方法数量会非常庞大。针对这个问题,我所知道的有两种解决方案,我姑且称之为第二种模型的两类变种:第一类变种就是

41、 partech的那种模型,简单的来说,就是把业务逻辑对象层和 DAO层合二为一;第二类变种就是干脆取消业务逻辑层,把事务控制前推至 Web层的 Action层来处理,下面分别分析一下两类变种的优缺点:第一类变种是合并业务逻辑对象和 DAO层,这种设计代码简化为 3个类,如下所示:一个 domain object:Item(同第二种模型的代码,省略)一个业务层接口:ItemManager(合并原来的 ItemManager方法签名和 ItemDao接口而来)一个业务层实现类:ItemManagerHibernateImpl(合并原来的 ItemManager方法实现和ItemDaoHibern

42、ateImpl)java代码: public interface ItemManager public Item loadItemById(Long id);public Collection findAll();public void updateItem(Item item);public Bid placeBid(Item item, User bidder, MonetaryAmount bidAmount, Bid currentMaxBid, Bid currentMinBid) throwsBusinessException;java代码: public class ItemMa

43、nagerHibernateImpl implements ItemManager extends HibernateDaoSupport public Item loadItemById(Long id) return (Item) getHibernateTemplate().load(Item.class, id);public Collection findAll() return (List) getHibernateTemplate().find(“from Item“);public void updateItem(Item item) getHibernateTemplate(

44、).update(item);public Bid placeBid(Item item, User bidder, MonetaryAmount bidAmount, Bid currentMaxBid, Bid currentMinBid) throwsBusinessException item.placeBid(bidder, bidAmount, currentMaxBid, currentMinBid);updateItem(item); / 确保持久化 item第二种模型的第一类变种把业务逻辑对象和 DAO层合并到了一起。考虑到典型的 web应用中,简单的 CRUD操作占据了业务

45、逻辑的绝大多数比例,因此第一类变种的优点是:避免了业务逻辑不得不大量封装 DAO接口的问题,简化了软件架构设计,节省了大量的业务层代码量。这种方案的缺点是:把 DAO接口方法和业务逻辑方法混合到了一起,显得职责不够单一化,软件分层结构不够清晰;此外这种方案仍然不得不对隐式依赖持久化的 domain logic提供封装方法,未能做到彻底的简化。总体而言,个人认为这种变种各方面权衡下来,是目前相对最为合理方案,这也是我目前项目中采用的架构第二种模型的第二类变种就是干脆取消 ItemManager,保留原来的Item,ItemDao,ItemDaoHibernateImpl 这 3个类。在这种情况下

46、把事务控制前推至 Web层的 Action去控制,具体来说,就是直接对 Action的 execute()方法进行容器事务声明。这种方式的优点是:极大的简化了业务逻辑层,避免了业务逻辑对象不得不大量封装 DAO接口方法和大量封装 domain logic的问题。对于业务逻辑非常简单的项目,采用这种方案是一个非常合适的选择。这种方式的缺点主要有 3个:1) 由于彻底取消了业务逻辑对象层,对于那些有重用需要的、多个 domain object和多个DAO参与的、复杂业务逻辑流程来说,你不得不在Action中一遍又一遍的重复实现这部分代码,效率既低,也不利于软件重用。2) Web层程序员需要对持久层

47、机制有相当高程度的了解和掌握,必须知道什么时候应该调用什么 DAO方法进行必要的持久化。3) 事务的范围被扩大了。假设你在一个 Action中,首先需要插入一条记录,然后再需要查询数据库,显示一个记录列表,对于这种情况,事务的作用范围应该是在插入记录的前后,但是现在扩大到了整个 execute执行期间。如果插入动作完毕,查询动作过程中出现通往数据库服务器的网络异常,那么前面的插入动作将回滚,但是实际上我们期望的是插入应该被提交。总体而言,这种变种的缺陷比较大,只适合在业务逻辑非常简单的小型项目中,值得一提的是 Hibernate的 caveatemptor就是采用这种变种的架构,大家可以参考一

48、下。综上所述,在采用 Rich Domain Object模型的三种解决方案中(第二模型,第二模型第一变种,第二模型第二变种),我认为权衡下来,第二模型的第一变种是相对最好的解决方案,不过它仍然有一定的不足,在这里我也希望大家能够提出更好的解决方案。,partech 提出了 实体控制对象 和 实体对象 两种不同层次的 Domain Object ,由于 Domain Object 可以依赖于 XXXFinderDAO,因此,也就不存在“大数据量问题” ,因此,整个 Domain 体系,对于实际业务表述的更为完整,更为一体化。我非常倾向这种方式。一般是这样的顺序:ClientServiceD ObjectDAODB至于哪些该放在哪里,基本有这样的原则:(就是 robbin的第二种了)DO封装内在的业务逻辑Service 封装外在于 DO的业务逻辑当然如果业务逻辑简单或者没有的话也可以:ClientD ObjectDAODB对于第二种的第一个变种固然是个好办法,但如 Robbin所说也有缺陷如果有多个 Servcie要调用 DAO的话,就有问题了。合并也意味中不能很好的重用说到底就是粒度的问题,分得细重用好,但类多、结构复杂、繁琐。分得粗(干脆用一个类干所有的事)重用差,但类少、结构简单。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 企业管理 > 管理学资料

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报