论坛首页 Java企业应用论坛

服务器端分包结构回顾

浏览 2872 次
精华帖 (0) :: 良好帖 (1) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2008-10-26  
现在很多的Java应用都采用Eric在《DDD》中提出的域分层结构,
所以大部分项目看起来像下面这个样子分包:
action
service
dao
domain
exception
util

最近做的这个项目也采用了类似的结构,
其中service和dao的关系是一个老生常谈的问题,
dao只对数据访问进行隔离,比如:Hibernate过时了,我们需要按一套全新的持久化方案,只需把Dao的实现类替换掉就行了。
service包括所有的业务逻辑,使用dao存取数据,并向Action功能提供服务。
然而,大部分企业应用中,业务逻辑就是对数据库的操作,
所以就出现了大量的service变成了dao的代理,
为此,有人提出,如果只是简单数据操作,action可以直接调用dao,因为同样保持着单向依赖。
但是,允许这样做后,dao函数的粒度较小,action变相的成了业务逻辑处理中心。
还有一个问题是,复杂的SQL语句,是业务还是数据操作?该放在dao,还是service?
其实放在dao或service, 都能说得通,
但我觉得应该放在service, SQL语句本身是业务逻辑,只是执行它的应该是数据操作接口,
如果dao只是作为数据操作接口,在现在数据自动映射处理框架的面前,是否有必要存在?
我比较赞同统一dao接口为一个特殊的服务, 如:PersistentService
持久化服务接口:
public interface PersistentService extends Service {

	void save(Entity entity);

	void batchSave(Collection<Entity> entities);

	void update(Entity entity);

	void batchUpdate(Collection<Entity> entities);

	void saveOrUpdate(Entity entity);

	void batchSaveOrUpdate(Collection<Entity> entities);

	void remove(Entity entity);

	void batchRemove(Collection<Entity> entities);

	void remove(Class<?> entityClass, Long id);

	void batchRemove(Class<?> entityClass, Collection<Long> entityIds);

	Entity get(Entity entity);

	Entity get(Class<?> entityClass, Long id);

	Entity get(Class<?> entityClass, String property, Serializable value);

	Collection<Entity> find(Entity entity);

	Collection<Entity> find(Class<?> entityClass, String property, Serializable value);

	Collection<Entity> find(String query);

	Page<Entity> findPage(Entity entity);

	Page<Entity> findPage(Class<?> entityClass, String property, Serializable value);

	Page<Entity> findPage(String query);

	......

}


然后,实现不同ORM框架的映射,如:
public class HibernatePersistentService implements PersistentService {

	......

}


或者SQL映射框架,如:
public class IbatisPersistentService implements PersistentService {

	......

}


或者非数据库持久化,如:
public class XmlPersistentService implements PersistentService {

	......

}



然后,在其它业务类服务基类中缺省由框架自动注入持久化服务:
public abstract class AbstractService implements Service {

	/**
	 * 日志输出接口
	 */
	protected final Logger logger = LoggerFactory.getLogger(getClass());

	/**
	 * 持久化服务
	 */
	protected PersistentService persistentService;

	// IoC注入接口
	public void setPersistentService(PersistentService persistentService) {
		this.persistentService = persistentService;
	}

}


业务类服务中使用如:
public class UserServiceImpl extends AbstractService implements UserService {

	public User login(String username, String password) {
		// 直接使用持久化服务接口
		User user = persistentService.get(User.class, "username" username);
		....
	}

}


这样统一后,
service表示无状态的服务模型,服务可以再依赖服务,并且像邮件发送等也应该成为服务,而不是util工具。
action表示有状态的功能模型,代表一个用户可具体操作的功能。
模块间服务模型共享,并定义好依赖关系。
模块间功能模型使用名称空间相互区隔,互不干扰。

如:
雇员管理服务:包括雇员增删改查接口,数据一致性检查等。
雇员管理功能:包括新增雇员的界面,界面控制,数据传输等。

提成管理功能,也可依赖雇员管理服务,通过服务获取提成雇员的信息。
但提成管理功能却不会依赖雇员管理功能,因为它不关心雇员信息是怎么维护的。

如果雇员信息是从HR系统同步过来的,那样就只需要雇员管理服务,而不需要雇员管理功能,或者同步过程就是雇员管理功能。

所以服务模型和功能模型应该分别打成jar包,便于部署。
   发表时间:2008-10-26  
javatar 写道
dao只对数据访问进行隔离,比如:Hibernate过时了,我们需要按一套全新的持久化方案,只需把Dao的实现类替换掉就行了。


这句话我总认为是听起来很美,不知道有没有人真正从中受益过。
如果hibernate过时了,那么我们开发的软件是否之前已经过时了呢。

真正要换掉dao层的时候,我想可能也不会像想象中那么简单的,其实DAO的代码相对倒是简单,更复杂的在于底层技术的一些细节。

甚至接口都要变化。

javatar 写道

还有一个问题是,复杂的SQL语句,是业务还是数据操作?该放在dao,还是service?
其实放在dao或service, 都能说得通,
但我觉得应该放在service, SQL语句本身是业务逻辑,只是执行它的应该是数据操作接口,


这个问题就更加复杂了,如果我们吧复杂查询放在DAO,那么我们的Service可就真的成了一个DAO的代理了,鸡勒。

如果我们放在service层,那么以前承诺的DAO层的可替换涉及也就落空了。你hibernate的HQL切换成其他查询语言,这个工作量可比我们换掉dao的代码复杂的多。


说一下我的做法。
DAO设计的时候给一个约定:只允许命名查询。
查询接口事制定查询名称和参数集合。这样,虽然查询还是在DAO做的,但是不是那种一个查询一个方法的方式。

这样做的好处就是Service不再像一个代理了。而DAO层也做了该做的事情。
还有一个好处就是,这样的DAO是可以自动生成的。

更多细节可以参看以前写的一个给予xdoclet的代码生成工具:
http://code.google.com/p/txdoc/downloads/list
http://txdoc.googlecode.com/svn/trunk/codegen/
这个项目虽然有点明日黄花了,一些想法还是有点参考价值。


0 请登录后投票
   发表时间:2008-10-28  
sql写在service还是dao,个人更倾向于写在dao,service操作都是面向对象的,传到dao的也是一个pojo对象。这样对于简单的crud,service确实会退化为一个dao的代理,而对于复杂的业务逻辑,涉及到多个表的操作的时候,复杂sql写在dao层,service看起来更加简洁。
0 请登录后投票
   发表时间:2008-10-30  
其实 DAO 确实应该只是接口,其实我觉得根本不应该叫 “DAO”,而应该叫 Persistence。因为持久数据的方式有很多种,数据库只是其中一个。
俺赞同梁兄的设计
0 请登录后投票
   发表时间:2008-10-30  
实际应用中,只有一种DaoImpl,什么HibernateDaoImpl,IbatisDaoImpl是不存在的.
所以实际开发中,我是No Dao Interface.
0 请登录后投票
   发表时间:2008-11-01  
其实怎么样设计都可以,主要考虑现实中的需要,Dao模式来源于《J2EE核心模式》,其主要目的是分离(或透明化)主动域实体(或充血模型)的持久化过程,在领域驱动设计中,Service + Dao的设计也可以作为“防腐战略”设计的一部分,自然有它的合理性,但实际很多时候,不需要这样的“过度”设计,因为通常项目的工期都很紧,我们有时候以快速开发为主,如果你觉得JSP + JavaBean + JDBC的方式更好,我也不反对。
0 请登录后投票
   发表时间:2008-11-05  
Service中操作的是对象,而DAO操作的是数据库.
0 请登录后投票
   发表时间:2008-11-05  
这个好像只能O/R mapping这样用。对象数据库没用过,应该也可以。
但是spring jdbc template, 或者 jdbc就不行。
0 请登录后投票
   发表时间:2008-11-05  
Entity get(Class<?> entityClass, Long id);  

为啥不是
Entity get(Class<?> entityClass, Object id);  
0 请登录后投票
   发表时间:2008-11-06  
只是举例,可以改为:
Entity get(Class<?> entityClass, Serializable id);
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics