軟體項目實訓及課程設計指導——如何合理地設計數據訪問服務層中的各個功能程序類
作者已經在本系列文章《軟體項目實訓及課程設計指導--如何正確地設計J2EE應用系統持久層中的各個組件結構及關係》中為讀者介紹了為什麼要設計和應用數據訪問服務接口的目的及如何設計該接口以真正達到利用數據訪問服務層組件隔離業務處理邏輯和數據訪問操作邏輯的應用效果。
作者將在本文為讀者介紹如何合理地設計數據訪問服務層中的各個程序類,包括程序類的結構及與持久層中的DAO組件和上層業務層內的業務組件之間的關係。
1、應用「門面設計模式」倡導的程序結構關係編程實現數據訪問服務組件
利用基於門面設計模式實現的數據訪問服務組件隔離軟體應用系統中業務處理邏輯和數據訪問操作邏輯,在各個業務邏輯處理組件中只需要與數據訪問服務組件進行交互,而不再需要與不同的DAO組件進行具體的交互。
這樣的設計方案可以降低整個軟體應用系統中的業務邏輯處理層和系統持久層中的數據訪問組件之間的藕合度,將使得軟體應用系統業務層組件的可重用性得到進一步地提高。
下圖所示為實現這樣的設計目標的UML類圖示例,在具體的編程實現中,應該要保證各個業務處理類只與數據訪問服務組件接口進行關聯,而在數據訪問服務接口實現組件中也應該只與各個數據訪問接口發現關聯——依賴倒置思想的具體應用。
在上述示例圖中的「數據訪問服務組件接口」及相關的實現類基於門面設計模式的設計思想而設計,考慮到本文章的篇幅有限,至於什麼是門面設計模式及如何編程實現門面設計模式、門面設計模式的編程原則和代碼實現示例等方面的詳細內容請讀者閱讀作者的《J2EE項目實訓——UML及設計模式》一書中的第7章「架構設計中的架構模式」章節中的有關內容。
2、正確地編程實現數據訪問服務組件和各個數據訪問組件之間關係的示例程序代碼
(1)首先,設計和實現數據訪問服務接口
如下為示例項目銀行帳戶信息管理系統項目中的數據訪問服務接口中部分方法的定義代碼示例,其中的selectAllAccountInfo()方法提供查詢返回某個用戶的所有帳戶信息,考慮到本文章的篇幅,數據訪問服務接口中的其它方法的定義在此省略。
package com.bluedream.webbank.service;
import java.util.ArrayList;
import com. bluedream.webbank.exception.WebBankException;
import com. bluedream.webbank.model.vo.AccountInfoVO;
public interface AccountDAOServiceInterface {
public ArrayList<AccountInfoVO> selectAllAccountInfo()
throws WebBankException;
// ... 其它方法的定義在此省略
}
(2)其次,再設計和實現數據訪問服務接口的具體功能實現類,為數據訪問服務接口中所定義的各個功能服務方法提供最終的功能實現。
如下為示例項目銀行帳戶信息管理系統項目中的數據訪問服務接口的具體功能實現類代碼示例,考慮到本文章的篇幅,方法內的具體功能實現細節的程序代碼在此省略沒有附錄。
package com. bluedream.webbank.service;
import java.util.ArrayList;
import com. bluedream.webbank.exception.WebBankException;
import com. bluedream.webbank.model.vo.AccountInfoVO;
public class AccountDAOServiceImple implements AccountDAOServiceInterface {
private AccountManageDAOInterfaceoneAccountManageDAOJDBCImple=null;
public ArrayList<AccountInfoVO> selectAllAccountInfo()
throws WebBankException{
// ... 具體的功能實現代碼在此省略
}
// ... 其他方法的功能實現代碼在此省略
}
(3)最後,正確地編程實現數據訪問服務實現組件類和各個數據訪問組件類之間的關係
在上述示例所示的數據訪問服務接口的具體功能實現類(AccountDAOServiceImple)代碼示例中通過包含數據訪問組件接口對象而實現數據訪問服務組件和各個數據訪問組件之間的關係(請見上述示例代碼中黑體所示的oneAccountManageDAOJDBCImple對象的定義代碼)——遵守「優先應用類之間的組合關係,少用程序類之間的繼承關係」的設計原則。
基於上面的設計原則,讀者在以後的軟體應用系統項目開發實現中不應該採用下面示例所示的繼承某個數據訪問組件的實現類的設計方案(請見下面程序代碼示例中黑體所示的代碼public class AccountDAOServiceImple extends AccountDAOServiceImple),因為面向對象OOP程序設計方法中的繼承關係會導致子類緊密依賴於其上層的基類。如下為採用繼承機制實現的代碼示例。
package com. bluedream.webbank.service;
import java.util.ArrayList;
import com. bluedream.webbank.exception.WebBankException;
import com. bluedream.webbank.model.vo.AccountInfoVO;
public class AccountDAOServiceImple extends AccountDAOServiceImple
implements AccountDAOServiceInterface {
public ArrayList<AccountInfoVO> selectAllAccountInfo()
throws WebBankException{
// ... 具體的功能實現代碼在此省略
}
// ... 其他方法的功能實現代碼在此省略
}
讀者可以通過上述兩種功能相同但採用不同設計風格編程實現的程序代碼示例,深刻領悟程序類關係設計中所倡導的「優先應用組合、儘量少用繼承」的設計原則。此設計原則大量地應用在GOF的23種設計模式中。
3、對各個數據訪問服務組件的實現代碼進一步重構——「找出共性,分離個性」
在軟體應用系統中的各個數據訪問服務組件中包含有類似功能實現的數據訪問邏輯是一種很常見的現象,軟體應用系統的開發人員此時應該要對軟體應用系統中的各個數據訪問服務組件的功能實現代碼進一步重構(reFactor)——「找出共性,分離個性」以減少程序代碼的重複度。
如下示圖為MyEclipse開發工具中所提供的程序代碼重構的功能菜單,MyEclipse開發工具全面地支持Martin Fowler在他的經典名著《重構:改善既有代碼的設計》(英文書名: Refactoring: Improving the Design of Existing Code)一書中所倡導代碼重構功能。
當然,軟體應用系統的開發人員還應該仔細地思考下面的有關問題:
1)怎樣合理地抽象出共性的數據訪問邏輯?
2)怎樣處理數據訪問服務層中的各個方法之間的相互調用?
3)怎樣處理數據訪問服務層中的各個服務方法的事務?
為此,在程序設計方面,開發人員應該將「共性」的數據訪問服務邏輯的程序代碼封裝到一個數據訪問服務基類中,而將「個性化」的數據訪問服務實現代碼放在對應的子類中。因為面向對象OOP程序設計方法中的「繼承與派生」是分離事物的「共性」和「個性」的常用設計手段。
下圖所示為體現該設計思想的UML類圖的示例圖,各個數據訪問服務子接口的實現類一方面實現各自的接口定義中的功能方法——它們代表「個性」的數據訪問服務邏輯的實現代碼,另一方面也繼承數據訪問服務基接口的實現類,這樣將可以在各個數據訪問服務子接口的實現類中重用數據訪問服務基接口實現類中的各個功能方法——它們代表「共性」的數據訪問服務邏輯的實現代碼。
下面的幾個程序代碼示例中的各個接口定義及有關的實現類的代碼體現了上述這樣的設計思想,為了減少本文章的篇幅,除掉了無關的方法定義和方法的功能實現代碼沒有附錄。
1)數據訪問服務基接口的程序代碼示例,在該接口中定義「共性」的數據訪問服務邏輯
package com.bluedream.daoService;
public interface BaseDAOService{
public void baseDAOServiceMethod();
}
2)數據訪問服務基接口的具體實現類的程序代碼示例,在該程序類中最終完成「共性」的數據訪問服務邏輯的功能實現
package com.bluedream.daoService;
public class BaseDAOServiceImle implements BaseDAOService{
public BaseDAOServiceImle() {
}
public void baseDAOServiceMethod() {
}
}
3)數據訪問服務基接口的某個子接口的程序代碼示例,在該接口中定義「個性」的數據訪問服務邏輯以滿足特定的應用功能
package com.bluedream.daoService;
public interface BaseDAOServiceDerivedInterface extends BaseDAOService{
public void derivedDAOServiceMethod();
}
4)數據訪問服務子接口的實現類代碼示例,在該程序類中最終完成「個性」的數據訪問服務邏輯的功能實現
package com.bluedream.daoService;
public class BaseDAOServiceDerivedInterfaceImple extends BaseDAOServiceImle
Implements BaseDAOServiceDerivedInterface {
public BaseDAOServiceDerivedInterfaceImple() {
}
public void derivedDAOServiceMethod() {
}
}