| 導購 | 订阅 | 在线投稿
分享
 
 
 

「面向切面(AOP)」與「面向對象(OOP)」(圖)

來源:互聯網  2008-05-31 11:18:03  評論

首先你要明確的一點,AOP和OOP是兩種不同的熟悉事物的角度,並不是說有了AOP就不要用OOP.AOP所關注的是傳統OOP不能優雅解決的問題.(程序員通常都是完美主義者,當解決某個問題不優雅的時候,那就意味著不完美.)下面將就一個簡單的例子來說明他們到底如何的不同.

作爲一個使用OOP多年的人來說,當我聽說AOP可以解決一些OOP一直都不能優雅地解決的問題時,我覺得應該去探個究竟了.對兩種技術的比較最能給我們實際應用提供見解.這裏我設計了一個例子:一個OOP應用,其中某些方面適合使用AOP.

本文展示了一個簡單的例子.一開始介紹了問題域,然後分別給出OOP與AOP的解決方案.後者使用了 JDK5.0,JUnit,和aspectWerkz.最後說明如何編寫代碼.讀完本文後,我希望你能知道AOP到底是什麽,解決什麽樣的問題.(由于作者在後面AOP的例子中使用了java5.0的批注(Annotation),建議讀者先有所了解. -- 譯者注).

問題域描述

一個軟件公司雇傭一個程序員,指定給他一個業務部門並要求他隨時向經理報告.當團隊成員完成他們的目標時,經理會給他們相應的獎金.公司所需要的方案必須能夠增加一個新的雇員並給當前的員工增加獎金.爲了方便,我們用CSV文件存儲數據.

「面向切面(AOP)」與「面向對象(OOP)」(圖)

圖1 解決方案模型

類Manager(經理)繼續自類Employee,包含一個額外的屬性,Managing PRoject.一個部門可能包含很多員工.多個部門構成了公司.暫不考慮公司這樣的一個類,因爲它在問題域之外.

解決方案設計

以下流程圖描述了解決方案設計.

「面向切面(AOP)」與「面向對象(OOP)」(圖)
點擊查看大圖

圖2 對象之間的交互(增加一個新的員工,指派給他一個部門和經理)

出于簡單的考慮,本文只關注必需的細節.當然你也可以深入代碼得到你想要的其他信息.

[link]http://www.devx.com/assets/sourcecode/13172.zip[/link]

EmployeeServiceTestCase,一個JUnit測試用例,模擬一個最終用戶,創建新員工記錄,指派部門和經理.它獲取所有可用的部門和經理數據並顯示在圖形界面上.爲了實例化域對象BusinessUnit和Manager,獲得的記錄將傳遞給工廠類.之後,通過給EmployeeService傳遞一個引用來創建一個Employee對象.這個服務類使用EmployeeFactory創建對象,並把這個對象傳給EmployeeRepository 來進行持久化操作.

應用程序中需要面向哪些"切面"

到目前爲止,對模型和設計的討論還限于一個較抽象的層面.現在,我轉向這個應用的其他方面 - 這對理解AOP的價值至關重要.

操作所需的資源

public static Set findAllBusinessUnits() throws RepositoryException {

Set businessUnits = new HashSet();

try {

FileReader businessUnitFile = null;

BufferedReader bufferedBusinessUnitFile = null;

try {

businessUnitFile = new FileReader(FILE_NAME);

bufferedBusinessUnitFile = new BufferedReader(businessUnitFile);

String businessUnitRecord;

while((businessUnitRecord = bufferedBusinessUnitFile.readLine()) != null) {

BusinessUnit businessUnit = BusinessUnitFactory.createBusinessUnit(businessUnitRecord);

businessUnits.add(businessUnit);

}

} finally {

if(bufferedBusinessUnitFile != null) {

bufferedBusinessUnitFile.close();

}

if(businessUnitFile != null) {

businessUnitFile.close();

}

}

} catch(IOException ioe) {

String message = "IOError. Unable to find Business Unit records";

logger.log(SEVERE, message, ioe);

throw new RepositoryException(message, ioe);

}

logger.log(INFO, "Manager Records returned:" + businessUnits.size());

return businessUnits;

}

上面的代碼通過FileReader和BUfferedReader來讀取CSV文件中的業務數據.

應用程序重複地從資源文件中取得數據然後在操作完成後釋放.我們會發現:去掉程序的這兩個"切面"將提高代碼的可讀性並達到一個更好的設計,因爲去掉這些"多余"的東西,剩下的代碼才是這個方法真正的精髓.這個方法的作用是讀取業務單位數據.所以不應該也不需要去知道"如何獲取和釋放資源以及這個過程中出現的異常"這個"切面".同樣地,使用AOP處理異常也變得不同.(後面將具體介紹)

持久層

傳統的OOP使用倉庫類(repository classes)來打理應用程序的持久層.即:

public class EmployeeRepository {

public static void createEmployee(Employee employee) throws RepositoryException {

//使用print writer把數據放入csv文件

}

public static String findEmployeeRecordById(String id) throws RepositoryException {

//使用file reader來獲得指定id的員工數據

}

public static Employee findEmployeeById(String id) throws RepositoryException {

//使用該方法獲取員工數據,Employee對象由工廠類創建

}

public static void updateEmployee(Employee employee) {

//更新員工數據

}

}

類EmployeeService 使用一個倉庫類給應用中相關雇員提供服務,在一個企業應用中,從域模型(domain model)中去掉持久層代碼是一種設計上的改進.模型設計者和程序員就可以關注各自的業務邏輯和持久層處理.後面你將會看到如何通過AOP來達到這樣的效果.

日志

刪除用于調試的日志代碼將會極大地改進代碼的可讀性.考慮下面的代碼片斷:

public Employee createEmployee(String name,

String contactNumber,

BusinessUnit businessUnit,

Manager manager)

throws EmployeeServiceException {

String id = createNewEmployeeId();

Employee employee =

EmployeeFactory.createEmployee(id, name, contactNumber, businessUnit, manager);

try {

EmployeeRepository.createEmployee(employee);

} catch(RepositoryException re) {

String message = "Created employee sUCcessfully:" + employee;

logger.log(SEVERE, message);

throw new EmployeeServiceException(message, re);

}

logger.log(INFO, "Created employee successfully:" + employee);

return employee;

}

上面的代碼裏包含了一個致命錯誤和一個成功信息.輸出日志這一"切面"同樣可以移到業務模型外獨立實現.

異常處理

異常處理的例子我這裏不再贅述,但這節已經通過上面的代碼討論了潛在的問題.當你調用EmployeeRepository 對象的createEmployee 方法時,你可能會得到一個RepositoryException異常.傳統的解決方法是,在這個類中處理.另一種方法是,當RepositoryException 異常被抛出時createEmployee 方法返回null,catch塊中的其他邏輯可以在類外處理這一錯誤.

錯誤處理在不同的情況中也會不同.但是,通過AOP可以區分開每種情況.

「面向切面(AOP)」與「面向對象(OOP)」(圖)
點擊查看大圖

圖3

圖3中描述了AOP方法的設計以及在一個更抽象的層次上類間的交互.你可以通過對比圖1和圖3來更好地理解AOP.

程序的目的是通過BusinessUnit對象讀取CSV文件中的記錄然後 填入類BusinessUnitService 中的map.使用AOP來填充這個map有點類似後門(backdoor)方法 -- 控制被委派給BusinessUnit 來讀取存儲介質中的記錄.

AOP就是定義一些切入點(pointcut)和處理方法(advice).一個"切入點"是源代碼中一個執行點.前面的例子定義了一個"切入點" --類BusinessUnitService中的findBusinessUnits方法.一個"處理方法"顧名思義就是當執行到某個"切入點"時的一塊代碼.類BusinessUnitPersistentAspect 包括advice方法findAllBusinessUnits,該方法從存儲介質中載入數據,然後使用工廠類創建BusinessUnit 對象.然後這個對象被加入map,map對象的引用通過BusinessUnitService 對象獲得."切入點"和"處理方法"組成了所謂的"切面(Aspect)"

爲了讀取存儲介質中的數據,OOP方法通過一個DAO類來做.而AOP中,你只要定義一個"切入點"和相應的"處理方法"來讀取數據.AOP框架會以advice的形式注入代碼,既可以在執行期也可以在編譯期.

總而言之,當類BusinessUnitService 中的findAllBusinessUnits 方法被調用時,AOP框架會在"切入點"處注入處理方法,通過BusinessUnit 對象預先讀取數據來填充map對象.這樣,持久層方面的代碼就可以移到業務代碼之外了.

新方法裏的"切面"

本節討論如何用AOP爲應用程序的各個"切面"建模

操作資源

類BusinessUnitPersistenceAspect 的持久方法使用了一個buffered reader.你甚至可以定義"切面"的"切面",但爲了簡單,這裏只關注類的查找方法.

@Aspect("perJVM")

public class BufferedFileReaderAspect {

@EXPression("execution(* org.javatechnocrats.aop.withaop.aspects.Busi

  首先你要明確的一點,AOP和OOP是兩種不同的熟悉事物的角度,並不是說有了AOP就不要用OOP.AOP所關注的是傳統OOP不能優雅解決的問題.(程序員通常都是完美主義者,當解決某個問題不優雅的時候,那就意味著不完美.)下面將就一個簡單的例子來說明他們到底如何的不同.      作爲一個使用OOP多年的人來說,當我聽說AOP可以解決一些OOP一直都不能優雅地解決的問題時,我覺得應該去探個究竟了.對兩種技術的比較最能給我們實際應用提供見解.這裏我設計了一個例子:一個OOP應用,其中某些方面適合使用AOP.      本文展示了一個簡單的例子.一開始介紹了問題域,然後分別給出OOP與AOP的解決方案.後者使用了 JDK5.0,JUnit,和aspectWerkz.最後說明如何編寫代碼.讀完本文後,我希望你能知道AOP到底是什麽,解決什麽樣的問題.(由于作者在後面AOP的例子中使用了java5.0的批注(Annotation),建議讀者先有所了解. -- 譯者注).      問題域描述      一個軟件公司雇傭一個程序員,指定給他一個業務部門並要求他隨時向經理報告.當團隊成員完成他們的目標時,經理會給他們相應的獎金.公司所需要的方案必須能夠增加一個新的雇員並給當前的員工增加獎金.爲了方便,我們用CSV文件存儲數據.    [url=/bbs/detail_1758840.html][img]http://image.wangchao.net.cn/it/1323510379129.jpg[/img][/url]   圖1 解決方案模型      類Manager(經理)繼續自類Employee,包含一個額外的屬性,Managing PRoject.一個部門可能包含很多員工.多個部門構成了公司.暫不考慮公司這樣的一個類,因爲它在問題域之外.      解決方案設計      以下流程圖描述了解決方案設計.    [url=/bbs/detail_1758840.html][img]http://image.wangchao.net.cn/it/1323510379276.jpg[/img][/url] 點擊查看大圖   圖2 對象之間的交互(增加一個新的員工,指派給他一個部門和經理)      出于簡單的考慮,本文只關注必需的細節.當然你也可以深入代碼得到你想要的其他信息.   [link]http://www.devx.com/assets/sourcecode/13172.zip[/link]      EmployeeServiceTestCase,一個JUnit測試用例,模擬一個最終用戶,創建新員工記錄,指派部門和經理.它獲取所有可用的部門和經理數據並顯示在圖形界面上.爲了實例化域對象BusinessUnit和Manager,獲得的記錄將傳遞給工廠類.之後,通過給EmployeeService傳遞一個引用來創建一個Employee對象.這個服務類使用EmployeeFactory創建對象,並把這個對象傳給EmployeeRepository 來進行持久化操作.      應用程序中需要面向哪些"切面"      到目前爲止,對模型和設計的討論還限于一個較抽象的層面.現在,我轉向這個應用的其他方面 - 這對理解AOP的價值至關重要.      操作所需的資源      public static Set findAllBusinessUnits() throws RepositoryException {   Set businessUnits = new HashSet();   try {   FileReader businessUnitFile = null;   BufferedReader bufferedBusinessUnitFile = null;   try {   businessUnitFile = new FileReader(FILE_NAME);   bufferedBusinessUnitFile = new BufferedReader(businessUnitFile);   String businessUnitRecord;   while((businessUnitRecord = bufferedBusinessUnitFile.readLine()) != null) {   BusinessUnit businessUnit = BusinessUnitFactory.createBusinessUnit(businessUnitRecord);   businessUnits.add(businessUnit);   }   } finally {   if(bufferedBusinessUnitFile != null) {   bufferedBusinessUnitFile.close();   }   if(businessUnitFile != null) {   businessUnitFile.close();   }   }   } catch(IOException ioe) {   String message = "IOError. Unable to find Business Unit records";   logger.log(SEVERE, message, ioe);   throw new RepositoryException(message, ioe);   }      logger.log(INFO, "Manager Records returned:" + businessUnits.size());   return businessUnits;   }      上面的代碼通過FileReader和BUfferedReader來讀取CSV文件中的業務數據.      應用程序重複地從資源文件中取得數據然後在操作完成後釋放.我們會發現:去掉程序的這兩個"切面"將提高代碼的可讀性並達到一個更好的設計,因爲去掉這些"多余"的東西,剩下的代碼才是這個方法真正的精髓.這個方法的作用是讀取業務單位數據.所以不應該也不需要去知道"如何獲取和釋放資源以及這個過程中出現的異常"這個"切面".同樣地,使用AOP處理異常也變得不同.(後面將具體介紹)      持久層      傳統的OOP使用倉庫類(repository classes)來打理應用程序的持久層.即:      public class EmployeeRepository {      public static void createEmployee(Employee employee) throws RepositoryException {   //使用print writer把數據放入csv文件   }      public static String findEmployeeRecordById(String id) throws RepositoryException {   //使用file reader來獲得指定id的員工數據   }      public static Employee findEmployeeById(String id) throws RepositoryException {   //使用該方法獲取員工數據,Employee對象由工廠類創建   }      public static void updateEmployee(Employee employee) {   //更新員工數據   }   }      類EmployeeService 使用一個倉庫類給應用中相關雇員提供服務,在一個企業應用中,從域模型(domain model)中去掉持久層代碼是一種設計上的改進.模型設計者和程序員就可以關注各自的業務邏輯和持久層處理.後面你將會看到如何通過AOP來達到這樣的效果.      日志      刪除用于調試的日志代碼將會極大地改進代碼的可讀性.考慮下面的代碼片斷:      public Employee createEmployee(String name,   String contactNumber,   BusinessUnit businessUnit,   Manager manager)   throws EmployeeServiceException {   String id = createNewEmployeeId();   Employee employee =   EmployeeFactory.createEmployee(id, name, contactNumber, businessUnit, manager);   try {   EmployeeRepository.createEmployee(employee);   } catch(RepositoryException re) {   String message = "Created employee sUCcessfully:" + employee;   logger.log(SEVERE, message);   throw new EmployeeServiceException(message, re);   }   logger.log(INFO, "Created employee successfully:" + employee);   return employee;   }      上面的代碼裏包含了一個致命錯誤和一個成功信息.輸出日志這一"切面"同樣可以移到業務模型外獨立實現.      異常處理      異常處理的例子我這裏不再贅述,但這節已經通過上面的代碼討論了潛在的問題.當你調用EmployeeRepository 對象的createEmployee 方法時,你可能會得到一個RepositoryException異常.傳統的解決方法是,在這個類中處理.另一種方法是,當RepositoryException 異常被抛出時createEmployee 方法返回null,catch塊中的其他邏輯可以在類外處理這一錯誤.      錯誤處理在不同的情況中也會不同.但是,通過AOP可以區分開每種情況.    [url=/bbs/detail_1758840.html][img]http://image.wangchao.net.cn/it/1323510379562.jpg[/img][/url] 點擊查看大圖   圖3      圖3中描述了AOP方法的設計以及在一個更抽象的層次上類間的交互.你可以通過對比圖1和圖3來更好地理解AOP.      程序的目的是通過BusinessUnit對象讀取CSV文件中的記錄然後 填入類BusinessUnitService 中的map.使用AOP來填充這個map有點類似後門(backdoor)方法 -- 控制被委派給BusinessUnit 來讀取存儲介質中的記錄.      AOP就是定義一些切入點(pointcut)和處理方法(advice).一個"切入點"是源代碼中一個執行點.前面的例子定義了一個"切入點" -- 類BusinessUnitService中的findBusinessUnits方法.一個"處理方法"顧名思義就是當執行到某個"切入點"時的一塊代碼.類BusinessUnitPersistentAspect 包括advice方法findAllBusinessUnits,該方法從存儲介質中載入數據,然後使用工廠類創建BusinessUnit 對象.然後這個對象被加入map,map對象的引用通過BusinessUnitService 對象獲得."切入點"和"處理方法"組成了所謂的"切面(Aspect)"      爲了讀取存儲介質中的數據,OOP方法通過一個DAO類來做.而AOP中,你只要定義一個"切入點"和相應的"處理方法"來讀取數據.AOP框架會以advice的形式注入代碼,既可以在執行期也可以在編譯期.      總而言之,當類BusinessUnitService 中的findAllBusinessUnits 方法被調用時,AOP框架會在"切入點"處注入處理方法,通過BusinessUnit 對象預先讀取數據來填充map對象.這樣,持久層方面的代碼就可以移到業務代碼之外了.      新方法裏的"切面"      本節討論如何用AOP爲應用程序的各個"切面"建模      操作資源      類BusinessUnitPersistenceAspect 的持久方法使用了一個buffered reader.你甚至可以定義"切面"的"切面",但爲了簡單,這裏只關注類的查找方法.   @Aspect("perJVM")   public class BufferedFileReaderAspect {      @EXPression("execution(* org.javatechnocrats.aop.withaop.aspects.Busi
󰈣󰈤
王朝萬家燈火計劃
期待原創作者加盟
 
 
 
>>返回首頁<<
 
 
 
 
 熱帖排行
 
王朝網路微信公眾號
微信掃碼關註本站公眾號 wangchaonetcn
 
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有