• 沒有找到結果。

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