现在很多的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
持久化服务接口:
然后,实现不同ORM框架的映射,如:
或者SQL映射框架,如:
或者非数据库持久化,如:
然后,在其它业务类服务基类中缺省由框架自动注入持久化服务:
业务类服务中使用如:
这样统一后,
service表示无状态的服务模型,服务可以再依赖服务,并且像邮件发送等也应该成为服务,而不是util工具。
action表示有状态的功能模型,代表一个用户可具体操作的功能。
模块间服务模型共享,并定义好依赖关系。
模块间功能模型使用名称空间相互区隔,互不干扰。
如:
雇员管理服务:包括雇员增删改查接口,数据一致性检查等。
雇员管理功能:包括新增雇员的界面,界面控制,数据传输等。
提成管理功能,也可依赖雇员管理服务,通过服务获取提成雇员的信息。
但提成管理功能却不会依赖雇员管理功能,因为它不关心雇员信息是怎么维护的。
如果雇员信息是从HR系统同步过来的,那样就只需要雇员管理服务,而不需要雇员管理功能,或者同步过程就是雇员管理功能。
所以服务模型和功能模型应该分别打成jar包,便于部署。
所以大部分项目看起来像下面这个样子分包:
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包,便于部署。