推 ghchen:感謝S大的意見,我會朝你說的方向去試試看 05/06 09:19
推 dream1124:請問第二段可以舉更具體的例子嗎? 很有意思 05/06 19:08
推 swpoker:但只能從runtime來偵測吧~頂多只在test case那邊測測 05/08 11:43
第二段的部分在實作上應該還挺直覺的,所以我才沒有直接給出範例。
如果要給個具體的例子,那就拿原帖中應用為例。假設所有 Repository 相關的
classes 都在 package demo.repositories 之下(含 subpackage);所有 Service
相關的 classes 都在 package demo.services 之下(含 subpackage)。
不能直接碰 repository classes 的原則是指,除了 repository classes 與
services classes 之外的所有 class 都不能夠直接去調用 repository classes
的任何 method,也不能存取任何 repository classes 的 field。
要強制遵守這個原則大致上可以這麼做(假設違例處拋出一個帶有提示訊息的
runtime exception 即可達到成效):
public aspect DontTouchModel {
pointcut manipulateRepository() : call(* demo.repositories..*.*(..));
pointcut readFieldOfRepository() : get(* demo.repositories..*.*);
pointcut writeFieldOfRepository() : set(* demo.repositories..*.*);
before() : manipulateRepository()
&& !within(demo.repositories..*) && !within(demo.services..*) {
throw new RuntimeException(
"Please don't touch repositories classes directly.");
}
before() : readFieldOfRepository()
&& !within(demo.repositories..*) && !within(demo.services..*) {
throw new RuntimeException(
"Please don't touch repositories classes directly.");
}
before() : writeFieldOfRepository()
&& !within(demo.repositories..*) && !within(demo.services..*) {
throw new RuntimeException(
"Please don't touch repositories classes directly.");
}
}
把整個 project 的 classes 拿來與 DontTouchModel 織在一起後,非 repository/
service classes 者不論如何拿到 repository classes 的 object/class,只要
他有把 reference casting 成 repository classes/interface 來使用,就會被
揪出來(除非他透過 reflection 去使用這些 reference,這就是第三段的部分)。
這種做法對於那些符合原則的 statement 不會添加 runtime 成本(因為這些碼完全
沒有被加工),只有不符合原則的部分有額外成本(其實也沒有啦,你根本就要他掛掉
了 :D)。
※ 編輯: sbrhsieh (1.172.225.226), 05/09/2014 17:14:33
推 ghchen:再次感謝S大的解說!! 05/10 09:46