Thinking in sky

--老贺的BLOG

  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  21 随笔 :: 0 文章 :: 35 评论 :: 0 Trackbacks
    因为Spring自带的sample离我们的实际项目很远,所以官方一点的model层模式展现就靠Appfuse了。

    但Appfuse的model层总共有一个DAO接口、一个DAOImpl类、一个Service接口、一个ServiceImpl类、一个DataObject.....大概只有受惯了虐待的人才会欣然接受吧。
    另外,Domain-Driven逢初一、十五也会被拿出来讨论一遍。

    其实无论什么模式,都不过是一种人为的划分、抽象和封装。只要在团队里理解一致,自我感觉优雅就行了。
     我的建议是,一开始DO和Manager一生一旦包演全场,DO作为纯数据载体,而Manager类放置商业方法,用 getHibernateTemplate()直接访问数据库,不强制基于接口编程。当某天系统复杂到你直觉上需要将DAO层和Service层分开时,再分开就好了。

    1.DataObject类
    
好听点也可以叫Domain Object。Domain Driven  Development虽然诱人,但因为Java下的ORM框架都是基于Data Mapper模式的,没有Ruby On Rails中那种Active Recorder的模式。所以,还是压下了这个欲望,Data Object纯粹作一个数据载体,而把数据库访问与商业逻辑操作统一放到Manager类中。

    2.Manager类
    我的Manager类是Appfuse中DAO类与Service类的结合体,因为:

    2.1 不想使用纯DAO
     以往的DAO是为了透明不同数据库间的差异,而现在Hibernate已经做的很好。所以目前纯DAO的更大作用是为了将来可以切换到别的ORM方案比如 iBatis,但一个Pragmaic的程序员显然不会无聊到为了这个机会不大的理由,现在就去做一个纯DAO层,项目又不是Appfuse那样为了 demo各种ORM方案而存在。

    2.2 也不想使用Service层来为Dao解耦
    在JPetStore里有一个很薄的Service层,Fascade了一堆DAO类,把这些DAO类的所有方法都僵硬的重复了一遍。理论上一个 Manager类可以管理数个Dao类,可以避免Dao之间直接耦合。但既然有Manager的情况下,商业逻辑都是写在Manager类的,那样子 Manager似乎还是调用另一个Manager比较妥当,调用裸Dao可能存在忽略了某些逻辑。所以,耦合又从Dao层升到Service层了。
     所以,除非你做的是超薄的不带逻辑的Service层,否则没有解耦的意义。
    何况,对一个不是死搬书的Designer来说,组件边界之内的类之间的耦合并不是耦合。

    3.去除不必要的基于接口编程
    众所周知,Spring是提倡基于接口编程的。
    但有些Manager类,比如SaleOrderManager ,只有5%的机会再有另一个Impl实现。95%时间里这两兄弟站一起,就像C++里的.h和.cpp,徒增维护的繁琐(经常要同步两个文件的函数声明),和代码浏览跳转时的不便(比如从Controler类跟踪到Service类时,只能跳转到接口类的相应函数,还要再按一次复杂的热键才跳转到实现类)
    连Martin Flower都说,强制每个类都分离接口和实现是过犹不及。只在有多个独立实现,或者需要消除对实现类的依赖时,才需要分离接口。

    3.1 DAO被强制用接口的原因
    Spring IOC本身是不会强制基于接口的,但DAO类一般要使用Spring的声明式事务机制,而声明式的事务机制是使用Spring AOP来实现的。Spring AOP的实现机制包括动态代理和Cgilib2,其中Spring AOP默认使用的Java动态代理是必须基于接口,所以就要求基于接口了。
    
    3.2 解决方法
    那就让Spring AOP改用CGLib2,生成目标类的子类吧,我们只要指定使用声明式事务的FactoryBean使用CGLib的方式来实现AOP,就可以不基于接口编程了。
    指定的方式为设置proxyTargetClass为true。如下:
<bean class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
id
="baseService"   abstract="true">
  
<property name="transactionManager" ref="transactionManager"/>
  
<property name="proxyTargetClass" value="true"/>

</bean>


又因为这些Service Bean都是单例,效率应该不受影响。

    4.总结
    对比Appfuse里面的5个类,我的Model层里只有VO作为纯数据载体,Manager类放商业方法。有人说这样太简单了,但一个应用,要划成几个 JSP,一个Controller,一个Manager,一个VO,对我来说已经足够复杂,再要往上架墙叠屋,恕不奉陪,起码在我的项目范围里不需要。 (但有很多项目是需要的,神佑世人)

    后记:迫于世人的压力,SpringSide暂时还是把DAO和Service层分开了,但依然坚持不搞那么多接口。
另外,尽量利用IDEA的代码生成热键,为Manager类生成delegate的Dao类方法。 



转自http://blog.csdn.net/qking93415981/archive/2007/08/08/1731676.aspx
posted on 2007-08-24 09:58 老贺 阅读(529) 评论(3)  编辑  收藏 所属分类: J2EE框架

评论

# re: 简化Spring(2)--Model层 2007-08-24 10:06 小贺
现在的SpringSide 2.0是把DAO和Service合在一起的,不知道以前的版本是怎么做的。 合在一起的类叫做Manager,继承自范型的DAO,如

public class UserManager extends HibernateEntityDao<User> {
// ....CRUD以外的其它商业方法
}

以前DAO里的CRUD等基本方法,现在放在了Manager类里而且是不可见的(因为是继承过来的),这样Manager里直接写以前Service里的商业方法,看起来就很清晰了。

由于采用范型DAO,我们就不需要去写具体的DAO实现,编码量就因此减少了很多。  回复  更多评论
  

# re: 简化Spring(2)--Model层 2007-08-24 10:13 小贺
以前做毕业设计时,仿照Appfuse的做法,model层总共有一个DAO接口、一个DAOImpl类、一个Service接口、一个ServiceImpl类、一个DataObject,写起来确实很麻烦,本来写的就是个小系统。

小系统嘛还是SpringSide的Model层简洁又清晰。其实Appfuse的DAO和Service的概念在SpringSide里还是有的,只是SpringSide把DAO和Service合成了一个Manager。  回复  更多评论
  

# re: 简化Spring(2)--Model层[未登录] 2008-03-18 10:04 vulcan
google到你的文章,发现我们对于DAO层和Service层的设计想法有些一样。
http://vulcan.javaeye.com/admin/blogs/160823
但是我遇到一个问题,不知道你遇到过没有,如果要直接对从范型接口继承来的方法签名进行声明式事务,却总不能成功。不知道兄弟有没有类似的问题,还是有其他的解决方法?我加你QQ,请教一下。  回复  更多评论
  


只有注册用户登录后才能发表评论。


网站导航: