当应用中需要使用到上十张表时,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设计。
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设计。