简化DAO设计的思想

来源:互联网 发布:下载cad绘图软件 编辑:程序博客网 时间:2024/05/19 13:22
当应用中需要使用到上十张表时,DAO的维护变得日益困难,主要表现在这几个方面: 
1)dao类的繁多,很多设计都是一个entity对应一个dao 
2)dao接口需要维护的method庞大。 
3)业务逻辑改变时,dao需要同时修改两个类文件(接口和实现类) 

出于上述问题,有必要从新设计dao包。要求 
1)减少dao类的数目,dao包暴露的接口稳定且易于扩展新的查询。 
2)减少dao接口的method 
3)可以动态增加dao提供的数据访问逻辑,比如增加相应的查询实现等等 

我的分析: 
可以使用Criteria,NamedQuery来构造复杂的查询逻辑。 
对于改动最多的read/find逻辑,可以作一个抽象设计,以提供动态增加的同时提供稳定的接口。 
对于update,create,delete逻辑,dao的设计遵循原子操作的原则,不在这些接口中实现复杂的业务逻辑。总体来说,这些接口的改动很少,也很容易规范。 

下面是一些设计的类代码: 
[code="java"] 
public interface QueryObject{ 
public void setNamedQuery(String qstring); 
public Object query(Session session,Set parameterCollection); 
public QueryCfg getQueryCfg(); 
public boolean validate(QuryCfg cfg,Set params) ; 
public void setValidatable(boolean bool); 
public booelan getValidatable(); 


public interface QueryCfg{ 
public List getParameterCfgs(); 
public String getName(); 
public void setName(String name); 



public interface Parameter{ 
public ParameterCfg getParameterCfg(); 
public String getValue(); 



public interface ParameterCfg{ 
public int getOrder(); 
public void setOrder(int order); 
public String getName(); 
public void setName(String name); 
public Type getType(); 
public void setType(); 



public interface Type{ 
public static final String PRIMITIVE_TYPE="primitive"; 
public boolean isPrimitive(); 
public Class getObjectType(); 
public String getValue(Object o); 




[/code] 
上面这些基本接口便是组成我的dao包的设计基架。虽然与普通dao实现比较起来,这个设计多了许多复杂度,在项目初期也需要一定工作量来编码实现这些构架,但是当在项目进展到中后期时,这个设计已经显露了它优良的设计风格,它与普通DAO的设计相比较,有如下优点: 
1)DAO的设计将会更加简洁,用一个DAO接口就可以实现所有entity的dao操作,可以动态扩展复杂查询。DAO设计: 
[code="java"]public interface DAO{ 
// find 可以根据 
public Object find(String namedQuery,Set parameters); 
public Object createEntity(Object entity); 
public Object updateEntity(Object entity); 
public void removeEntity(Object entity); 


//具体的实现可以整合到优秀的容器里面。比如spring 
publi class DAOImpl{ 
//.... 
public Object find(String name,Set ps){ 
return (Object)getHibernateTemplate().execute(new HibernateCallback() { 
public Object doInHibernate(Session session) throws HibernateException { 
return QueryLocator.getQueryObject(name).query(session,ps); 
}); 



//其中QueryLocator的实现可以用Spring,PicoContainer等等。 
[/code] 

2)业务逻辑层依赖于一个较稳定的DAO接口,使得可以更独立更快速的进行开发。 
在业务逻辑层,他们可以这样写代码: 

[code="java"]public class YourBusiness{ 
public void doBusiness(){ 
Set parameters=new LinkedHashSet(); 
parameters.add("firstName","test"); 
parameters.add(2,"test2"); 
List users=(List)getDao.find("findUserWithFullName",parameters); 


}[/code] 
这里的代码依赖于一个稳定的DAO接口,而不需要先实现DAO修改,再回来做相应的业务实现。 
3)可以支持参数检查,因为dao包的设计中加入了诸如ParameterCfg,QueryCfg等配置类,通过扩展这些抽象配置类实现我们定义的查询的配置,可以有效地帮助我们检查客户端的非法查询。 
4)工作量统计。可以计算一下,dao增加一个新的复杂的查询,需要增加一个QureyCfg类(可选,如果queryObject支持验证参数,则需要否则不需要),一个QueryObject类,增加Spring的一个Bean配置。 
传统的DAO设计的话,需要修改一个DAO接口,修改DAO实现。 
传统的DAO设计对于增加或者修改查询接口的话,工作量稍微少于我的设计。 
当系统的表为10个时,传统的DAo设计一般需要产生10个dao类(需要接口的话,为20个),如果一个dao类需要支持复杂的read查询为5个的话,对于查询的method,至少需要50个method实现。 
而我的设计除去Type这个底层稳定构架层次以外,仅仅需要一个DAO实现类,如果尽量采用NamedQuery,那么整体QueryObject类实现一般仅仅需要10个左右即可,QueryObject还有利于抽象复杂的查询,甚至包括需要使用到Criteria的QueryObject实现。比如这么一个抽象: 
[code="java"]public class CommonQuery implments QueryObject{ 
public Object query(Session session,Set parametes){ 
//验证参数合法性 
if(getValidatable()) 
validate(getQueryCfg(),parameters); 
List res = session.createCriteria(parameters.get("type")) 
.add( Expression.eq(parameters.get("queryParam"),parameters.get("value"))) 
.list(); 

}[/code] 
他可以抽象对某个表的某个字段等于某值的查询。 
当然这些设计需要涉及到一个参数集合规范的问题,这些都是可以在项目初期很快设计明确下来以形成正式的QueryObject设计规范文档。 

整体评估: 
当应用中的entity数量极大时,这种dao的设计将大大优越于传统的dao设计。
原创粉丝点击