簡化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設計。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章