活用設計樣式(一)

策略樣式、狀態樣式與橋接器樣式之應用

作者:吳立仲、謝嘉瑋

緣起:

        由於多數人學習「設計樣式(Design Pattern)」時,會把書上所展現的結構強加於所要做的系統上,而忽略書上所強調各個樣式所要使用的時機與使用的情形﹔然而,如果細看各個設計樣式的結構,會發覺有許多圖形是類似的,容易造成學習者的困惑。所以,希望透過本文,讓有意學習設計樣式者,可以更清楚理解各個樣式的不同。

        本文這次所要探討的分別是:狀態樣式(state pattern)、策略樣式(strategy)、  橋接器樣式(bridge)。透過駕駛對車所做的不同動作(換檔、加速(accelerate)、維修(maintain)),釐清這三種樣式的差別。請參見圖一:

圖一 車子的部分類別圖

 

共通結構─Composition(合成結構)

        這三個樣式之所以容易造成混淆,乃是因為他們有一個共通的結構,就是 Composition。所謂的 Composition 就是提出一個特定介面,讓 client 可以直接使用,而程式真正實作的部分,則透過實作介面的方式,產生一個或多個的 class。如下圖所示:

這種方式就好像將一件事情分成兩個部分完成。要完成某件事情時,必須結合兩個部分(呼叫 Interface 及實作 Interface)。透過這樣的方式,可達到黑箱式再利用的效果。

 

以下分別說明這三種樣式的使用動機與使用情形。

 

State Pattern 狀態樣式:

l          使用動機

由於車子會有加速的需求,但在不同檔的情況下,每個檔所能加速的極限又不一樣,所以,可以透過狀態樣式,來完成此一情況。

l          使用情形

在本例中(圖一),此一樣式出現於加速(Accelerate)的部分。當駕駛提出加速的要求時,車這個類別就可以直接使用檔這個介面中的 Accelerate 方法,然後,一檔、二檔分別實作了檔這個介面(當然還可以有更多的檔,依此類推)。由於在不同檔的情況下,每一檔加速的最高極限不一樣。透過這樣的方法,車子只需要了解「我要加速」,而不用理會我目前的狀態(檔)到底是什麼,我的最高速度又要如何控制。

l          特點

狀態樣式的重點在於根據不同的狀態產生不同的實作。所以使用它之前,要先確定它有不同的狀態﹔而每個狀態都有相類似但不相同的實作內容。如:車子在不同檔的加速。

 

Strategy Pattern 策略樣式:

l          使用動機

車子開了一段時間後,總是需要維修。要維修時,又可分為大修跟定期保養。然而,大修跟定期保養,有些動作是一樣的,只有些部分是不同的。此時,若能將相同的地方寫在一起,不同的地方透過一個介面來完成,那就簡單多了。

l          使用情形

在本例中,維修可分成定期保養跟大修,而他們的差別就只有在維修中的 changeTire 不同。若駕駛選擇大修,則他需要將四個輪子全部換掉﹔可是若只要定期保養,那他就不一定要將全部的輪子都換掉。如此一來,我們可以透過讓駕駛在做維修時,先選擇其所要維修的策略(大修或定期保養),再透過介面的方式,來實作不同的 changeTire

l          特點

此樣式最大的特點乃在於根據使用者所傳入不同的策略,改變行為。

 

Bridge Pattern 橋接器樣式:

l          使用動機

汽車有手排與自排兩種,而換檔時,會因為齒輪箱的不同而有不同的實作方式,但是,換檔的基本步驟卻是一樣的。所以,若能透過繼承與聚集關係(composition)的方法,就能以更順利的方式完成。

l          使用情形

手排汽車與自排汽車皆是車的子類別(subclass),手排換檔與自排換檔的實作內容可能引用父類別中換檔的方法來完成。

然而換檔的過程中,可能因為齒輪箱的差異,造成A廠牌與B廠牌的實作內容不相同,此時,可透過定義出一個介面的方式,來解決這些不一致的問題。