(下面是發(fā)在javaeye上的帖子,因?yàn)橛X(jué)的還有點(diǎn)意思,轉(zhuǎn)到blog來(lái),關(guān)于Domain和AOSD已經(jīng)有了一些新的想法)
應(yīng)用Domain開(kāi)發(fā)的系統(tǒng),通常把邏輯放在Domain Service層中,而Domain Service做兩個(gè)工作:
1. 和表現(xiàn)層通信,表現(xiàn)為把表現(xiàn)層的平面數(shù)據(jù)(VO)轉(zhuǎn)換為相關(guān)聯(lián)的Domain對(duì)象,把Domain對(duì)象計(jì)算的結(jié)果轉(zhuǎn)換成平面數(shù)據(jù)(VO)返回給表現(xiàn)層;
2.根據(jù)Use Case完成商業(yè)邏輯的調(diào)度。
以下主要討論Use Case的內(nèi)容。
通常Use Case所描述的Business Flow分為四種:Basic Flow,Alternate Flow,Exception Flow和Extension Flow。
雖然Business Flow可能包含很多領(lǐng)域?qū)ο螅捎诿總€(gè)use case的目標(biāo)帶有濃厚的領(lǐng)域邏輯,因而可以通過(guò)分析提煉出一個(gè)主domain對(duì)象。然后重組轉(zhuǎn)換來(lái)自BA或者PM的BP設(shè)計(jì)文檔,使其中的Basic Flow基于主domain對(duì)象,而把 Alternate Flow,Exception Flow和 Extension Flow基于其它的Domain Service和Domain Object(當(dāng)然包括Util objects), 最后利用AOP把Alternate Flow, Exception Flow和Extension Flow 與Basic Flow在Service層組織起來(lái)。
使用AOP來(lái)組織Use Case時(shí),與使用AOP組織技術(shù)問(wèn)題(比如日志,權(quán)限檢查和事務(wù)處理等)不同。
在AOP組織技術(shù)問(wèn)題時(shí),我們不關(guān)心join point的目標(biāo)對(duì)象和目標(biāo)方法以及入口參數(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
>
我們不關(guān)心參數(shù),或者在一些方法重載的地方利用參數(shù)來(lái)識(shí)別區(qū)分我們的方法入口。
但當(dāng)我們利用AOP來(lái)組織Use Case時(shí)我們關(guān)心目標(biāo)對(duì)象和目標(biāo)方法以及入口參數(shù)。因?yàn)锳OP所要織入的方法是另一個(gè)Use Case是另一個(gè)Biz Flow。(這個(gè)在AOSD中顯示討論的不多,只有在12章12.4.中有提到)
比如我們要在轉(zhuǎn)帳成功后發(fā)手機(jī)短信通知客戶。那么在沒(méi)有用AOP代碼中我們這樣寫(xiě):
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){

}
}
事實(shí)用User Case的觀點(diǎn)分析,發(fā)送短信通知是另一個(gè)use case,是轉(zhuǎn)帳這個(gè)use case的extend flow。用AOP的方法應(yīng)該如下:
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);
}
}

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



















我們不關(guān)心參數(shù),或者在一些方法重載的地方利用參數(shù)來(lái)識(shí)別區(qū)分我們的方法入口。
但當(dāng)我們利用AOP來(lái)組織Use Case時(shí)我們關(guān)心目標(biāo)對(duì)象和目標(biāo)方法以及入口參數(shù)。因?yàn)锳OP所要織入的方法是另一個(gè)Use Case是另一個(gè)Biz Flow。(這個(gè)在AOSD中顯示討論的不多,只有在12章12.4.中有提到)
比如我們要在轉(zhuǎn)帳成功后發(fā)手機(jī)短信通知客戶。那么在沒(méi)有用AOP代碼中我們這樣寫(xiě):























事實(shí)用User Case的觀點(diǎn)分析,發(fā)送短信通知是另一個(gè)use case,是轉(zhuǎn)帳這個(gè)use case的extend flow。用AOP的方法應(yīng)該如下:


















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