5. 範例與測試
5.1 特殊化結果
State Pattern
State pattern 的程式範例引用於[16]的套件 “oozinoz.carousel2”。我們對於它的 特殊化策略是將 State 的宣告(@State_State@Declaration)複製到@State_Context 的 內容中,並將@Context 類別當中的@Request 方法進行修改。將呼叫@Handle 方 法修改成 if 的敘述句,判斷呼叫的變數屬於哪個 State 的物件,而 if 的內容則是 被呼叫的方法的內容。在這個修改下,我們可以刪除@State_State 底下的@Decla- ration,還有每個@ConcreteState 的@Handle 內容。
該pattern 的 UML 設計可以參考圖 5-1,我們將撰寫 UML 產生的程式碼,讓 他有state pattern 的內容。撰寫後的程式碼可見表 5-1,我們將運用表 5-2 的內容 作為特殊化的命令。再經過特殊化程序處理後,可以得到一個特殊化後的程式碼(表 5-3)
這樣的特殊化修改我們省去兩次方法的呼叫,換來的是 if 判斷是的負擔,在
53
State 的數量不多的情況下則在執行速度上有些微的提升,而類別@State_Context 的檔案雖然會擴大,但能刪去所有類別@ConcreteState 的@Handle 內容,來獲得空 間上的改善。
圖 5-1 : 設計完成的 state pattern UML diagram
Context 1
2 3 4 5 6 7 8 9 10 11 12 13 14
@State_Context public class Door { @StateField
private DoorState mDoorState = DoorState.CLOSED;
@Request
public void TouchOnDoor () { mDoorState.Touch(this);
}
@Useless
public void setDoorState (DoorState val) { this.mDoorState = val;
} }
54
public interface DoorState { @Declaration
public static final DoorState CLOSED = new CLOSED();
@Declaration
public static final DoorState OPENED = new OPENED();
@Handle
public class CLOSED implements DoorState { @Handle
public class OPENED implements DoorState { @Handle
55
Copy @State_State()@Declaration(ALL:) @State_Context();
Modify @State_Context()@Request(ALL:) {
Convert @State_Context()@StateField().@State_State(TYPEOF:)@Handle(ALL:) To
"if( <@State_Context(ORIGINAL:)@StateField(ORIGINAL:)> instanceof <@State_ConcreteState(IFLIST:ALL:)>) {
<Inline @State_Context(ORIGINAL:)@StateField(ORIGINAL:).@State_ConcreteState(CORRESPONDING:)@Handle(ORIGINAL:)>
}"(IFLIST:) public class Door { @StateField
private DoorState mDoorState = DoorState.CLOSED;
@Declaration
public static final DoorState CLOSED = new CLOSED();
@Declaration
public static final DoorState OPENED = new OPENED();
@Request
表 5-3 :特殊化 state pattern 後的 Door.java (@State_Context)
56
Strategy Pattern
Strategy Pattern 的結構與 State Pattern 類似,因此特殊化的方法可以如同 State 的操作,將@contextInterface 呼叫 Strategy 利用 if 進行修改。在這次的特殊化範例 我們不使用特殊化state 的方法,我們將特殊化的重心往更上層修正,也就是呼叫
@StrategyMethod 的部分,在 headfirst 的 strategy 範例中,加入了使用 simulate strategy 的部分,因為 strategy 方法的呼叫由一個 reference 控制,我們改成直接呼 叫@StrategyMethod。
Strategy pattern 的 UML 設計可以參考圖 5-2,撰寫後的程式碼可見表 5-5,
我們運用表 5-4 的內容作為特殊化 strategy pattern 的命令。再經過特殊化程序處理 後,可以得到一個特殊化後的程式碼(表 5-6 和表 5-7)
從這個修改省去了一次的方法呼叫,我們引入@Strategy_User 的內容到
@Strategy_Context 當中,因為不會再使用到@Strategy_User 的部份內容,所以可 以刪去其中的定義。在class 的檔案大小上我們省下的一段方法的宣告。
圖 5-2 : 設計完成的 strategy pattern UML diagram
57
Modify @Strategy_Context()@contextInterface(ALL:) {
Convert @Strategy_Context()@Strategy_User_Reference(ALL:).@Strategy_User(TYPEOF:)@CallStrategy () To "<@Strategy_Context@Strategy_User_Reference(ORIGINAL:)>.
<@Strategy_User(NAME:Duck)@Strategy_Reference()>.<@Strategy_Strategy()@StrategyMethod()>
"
} ;
Modify @Strategy_Context()@contextInterface(ALL:) {
Convert @Strategy_Context()@Strategy_User_Reference(ALL:).@Strategy_User(TYPEOF:) @Set_Strategy () To "<@Strategy_Context@Strategy_User_Reference(ORIGINAL:)>.
<@Strategy_User(NAME:Duck)@Strategy_Reference()> = new FlyByRocket();
"
} ;
Delete @Strategy_User()@Set_Strategy() ; Delete @Strategy_User()@CallStrategy() ;
表 5-4 : 特殊化 strategy pattern 使用的命令
public interface FlyBehavior { @StrategyMethod
public class FlyByRocket implements FlyBehavior { @StrategyMethod
public class FlyNoWay implements FlyBehavior { @StrategyMethod
public void fly() {System.out.println("I can't fly");}
}
58 public class Duck {
@Strategy_Reference
FlyBehavior flyBehavior;
public class DuckSimulate { @Strategy_User_Reference
public Duck mallard = new DuckModel();
59
public class DuckSimulate { @Strategy_User_Reference
public Duck mallard = new DuckModel();
表 5-6 : 特殊化後的 DuckSimulate.java (@Strategy_Context) 1 public class Duck {
@Strategy_Reference
FlyBehavior flyBehavior;
public Duck() {}
}
表 5-7 : 特殊化後的 Duck.java (@Strategy_User)
TemplateMethod Pattern
在TemplateMethod 的設計上,Context 呼叫@AbstractClass 的@templateMethod 應該是由一連串固定的方法呼叫構成,而藉由@ConcreteClass 來編輯細節的不同,
因此我們將@templateMethod 當中呼叫方法用之前 if 的敘述句引入,而沒有被 override 的方法將可以唯一存在,這樣的修改同樣會有上述的優點與改善。
TemplateMethod pattern 的 UML 設計可以參考圖 5-3,撰寫後的程式碼可見表 5-9,我們運用表 5-9 的內容作為特殊化 TemplateMethod pattern 的命令。再經過特 殊化程序處理後,可以得到一個特殊化後的程式碼(表 5-10)
60
圖 5-3 : 設計完成的 TemplateMethod pattern UML diagram
Modify @TemplateMethod_AbstractClass()@templateMethod() {
Convert @TemplateMethod_AbstractClass()@generalOperation(ALL:) To
"<inline @TemplateMethod_AbstractClass(ORIGINAL:)@generalOperation(ORIGINAL:)>"
}
Modify @TemplateMethod_AbstractClass()@templateMethod() {
Convert @TemplateMethod_AbstractClass()@primitiveOperation (ALL:) To
"if( this instanceof <@TemplateMethod_ConcreteClass(IFLIST:ALL:)>) {\n
<inline @TemplateMethod_ConcreteClass(CORRESPONDING:)@primitiveOperation1(ORIGINAL:)>
}"(IFLIST:) }
Delete @TemplateMethod_AbstractClass()@primitiveOperation(ALL:)
表 5-8 : 特殊化 TemplateMethod pattern 使用的命令
61 public abstract class CaffeineBeverage { @templateMethod
@primitiveOperation public abstract void brew ();
@primitiveOperation
public abstract void addCondiments ();
public class Tea extends CaffeineBeverage { @primitiveOperation
public void brew () {
System.out.println("Steeping the tea");
}
@primitiveOperation
public void addCondiments () {
public class Coffee extends CaffeineBeverage { @primitiveOperation
public void brew () {
62
System.out.println("Dripping Coffee through filter");
}
@primitiveOperation
public void addCondiments () { public abstract class CaffeineBeverage { @templateMethod
表 5-10 : 特殊化後的 CaffeineBeverage.java (@TemplateMethod_abstract)
63