廢話:
預料中的日志3暫時生產不出來,話說難產就好,別夭折就行,有點掉價哦,呵呵。
因為有些東西還沒有想清楚。那就先搞個四吧,這個東西還是清楚那么一點的。
一版描述:
項目需求 |
使每個servlet能對用戶訪問權限進行檢查。簡單來說,就是要給每個servlet加個鎖,有鑰匙的用戶才能訪問。 |
而項目中用戶所謂的訪問權限是基于他擁有的角色。也就是說,servlet對用戶訪問權限的檢查,就是對他所擁有角色的檢查。暫時,每個用戶只能擁有一個角色。
項目的角色很多,但是在web端暫時只有如下的三種:
既然這樣,servlet的加鎖方式就有:
servlet加鎖方式 |
游客,學生,教師, 游客或學生,游客或教師,學生或教師, 游客或學生或教師 |
注:上面的“游客”就是“游客角色有權訪問”的意思,依此類推。
這里只有關系“或”(||),如果一個servlet的加鎖方式是“學生或教師”,也就是說擁有學生或教師角色的用戶都可以訪問它。關系“與”(&&)在這里不太可能存在,因為沒有需求說:某個servlet一定只能由“既是學生又是教師的用戶”才能訪問,而且前面也說了,暫時一個用戶“有且只有”一個角色。
So we can get following function:
“加鎖方式數” = 2的“角色數”次方 - 1
“加鎖方式數”是關于“角色數”的指數函數,也就是說它是關于“角色數”成“指數級”增長的,應該說很快了吧。
3個角色就有2的3次方-1個,也就是7個加鎖方式。
|
運用OO的最基本方式,就是封裝對象。既然有為servlet“看門”的責任,那就把這個責任封裝成一個對象,用個俗名:validator。
接著,運用共性和個性的分析方法,既然有那么多種不同的看門方式(加鎖方式),那就搞一個接口,然后讓各種“不同”都實現這個接口,形成子類。那就有下面的圖:

可以看到,由于有7個加鎖方式,那就要有7個子類。每個子類根據自己邏輯override接口的validate方法。
這樣,對于一個servlet,想讓它上什么樣的鎖,只要讓它拿到對應的子類的引用即可,如下圖中的ClientServlet,我們規定只能有“學生或教師”才能訪問它。它的部分代碼便是:

1
//new對應的Validator接口的子類。
2
//這里是學生或教師可訪問,因此要new Student_Or_Teacher_Validator
3
Validator validator = new Student_Validator();
4
//然后調用驗證方法就可以了
5
boolean ok = validator.validate();
至此,第一個解決方案就出來了。
思考:
不足 |
validator接口的子類數目隨“角色數”成“指數級”增長,數量太多;而且子類中重復邏輯的代碼很多,如“Student_Or_Teacher_Validator”就重復了“Student_Validator”和“Teacher_Validator”的邏輯,萬一“Student_Validator”的邏輯要改,只要涉及Student的子類都要跟著改,維護上不方便。 |
進一步改進的可能 |
“Student_Or_Teacher_Validator類”的validate方法很大程度上就是“Student_Validator類”的validate方法和“Teacher_Validator類”的validate方法“或操作”出來的結果。
因此,能不能考慮由“Student_Validator類的validate方法”和“Teacher_Validator的validate方法”動態的構造一個功能如“Student_Or_Teacher_Validator類的validate方法”。
這樣,“Student_Or_Teacher_Validator”就可以省略了,只剩下一些原子的“角色類”。要實現Student_Or_Teacher_Validator的驗證功能,拿Student_Validator和Teacher_Validator裝配一下就可以了。 |
結論,需要根據實際情況,動態的改變(裝配)“Validator接口對象”的validate方法。
第一個火花就是“裝飾模式”。它可以讓客戶端動態的組裝對象的方法。真神奇!
第二版來啦

注:上圖中出現了AndRelation和And的一系列角色類,可以暫時省略不看,因為前面說了,現在還沒有“與”關系這個需求。只看Or的就可以。
我喜歡叫這個模式為洋蔥模式,一層包一層,最外層對象某方法的邏輯是由內部一層一層對象的同一方法組合出來的。
使用了這個模式,便不用如一版那樣實現那么多子類,只要實現幾個“角色類”即可,這里有3個(學生角色:Or_Student、教師角色:Or_Teacher、游客角色:Or_Guest)。所有一版中別的子類都可以由這3個組裝出來。
如要生成一版中的Student_Or_Teacher_Validator對象,可以用Or_Student和Or_Teacher兩個對象“Or”出來:
1
Validator validator = new Or_Student(new Or_Teacher(OrRelation(req)));
如要生成一版中的Guest_Or_Student_Or_Teacher_Validator對象,可以用Or_Student、Or_Teacher和Or _Guest三個對象“Or”出來:
1
Validator validator = new Or_Student(new Or_Teacher(new Or_Guest(OrRelation(req))));
這種一層包一層的new方式,是不是很像洋蔥?第一次看是很不習慣,看多了就覺得習慣了。
對客戶端的影響:
一版中,客戶端要什么樣的驗證類,就直接使用具體類。
二版中,客戶端要什么樣的驗證類,它的工作多了那么一丁點,它需要先組裝一下,正如上面的例子。這種組裝的方法很易于理解和使用,不會給客戶端帶來任何的不便。如果實在覺得客戶端組裝不出來(傻B客戶端),也可以搞個工廠給它supply!
優點:
相對一版最明顯的優點就是類的數目少了很多。
一版不是說“指數級”嗎?這里只是線性的了。假設某一天系統拓展到有10個角色,一版就有2的10次方那么多個,也就是1024個驗證類。
而二版還是10個角色類,別的都可以在客戶端使用的時候,動態的組裝
更重要的是代碼結構好了,重復邏輯少了。每個邏輯都以最atomic的大小放到最應該的地方。
進而,維護的代價少多了。如某天“教師角色”的驗證邏輯發生了變化,只要改動Or_Teacher一個地方即可。
MARCO ZHANG 2006年2月18日23:49:56