(下面是發(fā)在javaeye上的帖子,因為覺的還有點意思,轉到blog來,關于Domain和AOSD已經(jīng)有了一些新的想法)
應用Domain開發(fā)的系統(tǒng),通常把邏輯放在Domain Service層中,而Domain Service做兩個工作:
1. 和表現(xiàn)層通信,表現(xiàn)為把表現(xiàn)層的平面數(shù)據(jù)(VO)轉換為相關聯(lián)的Domain對象,把Domain對象計算的結果轉換成平面數(shù)據(jù)(VO)返回給表現(xiàn)層;
2.根據(jù)Use Case完成商業(yè)邏輯的調度。
以下主要討論Use Case的內容。
通常Use Case所描述的Business Flow分為四種:Basic Flow,Alternate Flow,Exception Flow和Extension Flow。
雖然Business Flow可能包含很多領域對象,由于每個use case的目標帶有濃厚的領域邏輯,因而可以通過分析提煉出一個主domain對象。然后重組轉換來自BA或者PM的BP設計文檔,使其中的Basic Flow基于主domain對象,而把 Alternate Flow,Exception Flow和 Extension Flow基于其它的Domain Service和Domain Object(當然包括Util objects), 最后利用AOP把Alternate Flow, Exception Flow和Extension Flow 與Basic Flow在Service層組織起來。
使用AOP來組織Use Case時,與使用AOP組織技術問題(比如日志,權限檢查和事務處理等)不同。
在AOP組織技術問題時,我們不關心join point的目標對象和目標方法以及入口參數(shù)。比如:
public class BankServiceImpl implements BankService{
public void transfer(UserAccount src, UserAccount dist,
BigDecimal amount)throws Exception{
src.subtract(amount);
dist.add(amount);
}
//Other code goes here
}
<
bean id
=
"
BankService
"
class
=
"
org.
springframework.transaction.interceptor.TransactionProxyFactoryBean
"
>
<
property name
=
"
transactionAttributes
"
>
<
props
>
<
prop key
=
"
transfer
"
>
PROPAGATION_REQUIRED
</
prop
>
</
props
>
</
property
>
</
bean
>
我們不關心參數(shù),或者在一些方法重載的地方利用參數(shù)來識別區(qū)分我們的方法入口。
但當我們利用AOP來組織Use Case時我們關心目標對象和目標方法以及入口參數(shù)。因為AOP所要織入的方法是另一個Use Case是另一個Biz Flow。(這個在AOSD中顯示討論的不多,只有在12章12.4.中有提到)
比如我們要在轉帳成功后發(fā)手機短信通知客戶。那么在沒有用AOP代碼中我們這樣寫:
public class BankServiceImpl implements BankService{
public void transfer(UserAccount src, UserAccount dist,
BigDecimal change)throws Exception{
src.subtract(change);
dist.add(change);
SMSService.sendSMS(src, change);
SMSService.sendSMS(dist, change);
}
//Other code goes here
}
Public class SMSService {
public static void sendSMS(UserAccount user, BigDecimal change){
Long phone = user.getPhoneNumber();
BigDecimal balance = user.getBalance();
send(phone, change, belance)
}
private static void send(Long phone, change, balance){

}
}
事實用User Case的觀點分析,發(fā)送短信通知是另一個use case,是轉帳這個use case的extend flow。用AOP的方法應該如下:
public class BankServiceEx {
public static void notify(UserAccount src, BigDecimal change) {
SMSService.sendSMS(src, change);
}
//Other code goes here
}
public aspect BankServiceAspect {
pointcut transfer():call(void BankService.transfer(..));
after(UserAccount src, UserAccount dist, BigDecimal change) returning : transfer() && args(src, dist, change){
BankServiceEx.notify(src, change);
BankServiceEx.notify(dist, change);
}
}

這樣我們完成了兩個用例的分離,兩個用例獨立,可以重用和測試。比如上述短信通知用例其實可以被重用到其它情況如:存款,消費,以及銀行分紅等等。
不過可能面臨一個情況是,兩個獨立用例的代碼部分都可能用到某個對象, 那么在兩個用例中可能重復一部分代碼。雖然從概念上看,不應該重復(在使用用舊的方法實現(xiàn)時不會重復),但從不同use case看,這個重復是值得的。曾經(jīng)考慮利用代碼生成,直接獲得Local Variable,這樣可以減少重復,但是這個想法是錯誤的,不僅僅是實現(xiàn)上的困難,更重要在于,分離出的發(fā)送短信用例便綁定了轉帳用例,依賴于轉帳用例,而無法獨立重用和測試。
這樣,對象、方法以及方法參數(shù)構成了一個完整的pointcut,成為不同用例切片的共同入口,相當于一個占位符。這個時候就需要不同的用例實現(xiàn)人員協(xié)調好該入口。
應用Domain開發(fā)的系統(tǒng),通常把邏輯放在Domain Service層中,而Domain Service做兩個工作:
1. 和表現(xiàn)層通信,表現(xiàn)為把表現(xiàn)層的平面數(shù)據(jù)(VO)轉換為相關聯(lián)的Domain對象,把Domain對象計算的結果轉換成平面數(shù)據(jù)(VO)返回給表現(xiàn)層;
2.根據(jù)Use Case完成商業(yè)邏輯的調度。
以下主要討論Use Case的內容。
通常Use Case所描述的Business Flow分為四種:Basic Flow,Alternate Flow,Exception Flow和Extension Flow。
雖然Business Flow可能包含很多領域對象,由于每個use case的目標帶有濃厚的領域邏輯,因而可以通過分析提煉出一個主domain對象。然后重組轉換來自BA或者PM的BP設計文檔,使其中的Basic Flow基于主domain對象,而把 Alternate Flow,Exception Flow和 Extension Flow基于其它的Domain Service和Domain Object(當然包括Util objects), 最后利用AOP把Alternate Flow, Exception Flow和Extension Flow 與Basic Flow在Service層組織起來。
使用AOP來組織Use Case時,與使用AOP組織技術問題(比如日志,權限檢查和事務處理等)不同。
在AOP組織技術問題時,我們不關心join point的目標對象和目標方法以及入口參數(shù)。比如:



















我們不關心參數(shù),或者在一些方法重載的地方利用參數(shù)來識別區(qū)分我們的方法入口。
但當我們利用AOP來組織Use Case時我們關心目標對象和目標方法以及入口參數(shù)。因為AOP所要織入的方法是另一個Use Case是另一個Biz Flow。(這個在AOSD中顯示討論的不多,只有在12章12.4.中有提到)
比如我們要在轉帳成功后發(fā)手機短信通知客戶。那么在沒有用AOP代碼中我們這樣寫:























事實用User Case的觀點分析,發(fā)送短信通知是另一個use case,是轉帳這個use case的extend flow。用AOP的方法應該如下:


















這樣我們完成了兩個用例的分離,兩個用例獨立,可以重用和測試。比如上述短信通知用例其實可以被重用到其它情況如:存款,消費,以及銀行分紅等等。
不過可能面臨一個情況是,兩個獨立用例的代碼部分都可能用到某個對象, 那么在兩個用例中可能重復一部分代碼。雖然從概念上看,不應該重復(在使用用舊的方法實現(xiàn)時不會重復),但從不同use case看,這個重復是值得的。曾經(jīng)考慮利用代碼生成,直接獲得Local Variable,這樣可以減少重復,但是這個想法是錯誤的,不僅僅是實現(xiàn)上的困難,更重要在于,分離出的發(fā)送短信用例便綁定了轉帳用例,依賴于轉帳用例,而無法獨立重用和測試。
這樣,對象、方法以及方法參數(shù)構成了一個完整的pointcut,成為不同用例切片的共同入口,相當于一個占位符。這個時候就需要不同的用例實現(xiàn)人員協(xié)調好該入口。