前言 在 設計模式
中, 一個最基本的原則 少用繼承,多用合成
。所以我們有了 Strategy Pattern (策略模式) 和 其他有用的設計模式,在這邊主要是想要談如何透過 Swift
來實作策略模式。
關於 Strategy Pattern 策略模式
定義一系列演算法,將每一個演算法封裝起來,並讓它們可以相互替換。策略模式讓算法獨立於使用它的客戶而變化。
策略模式包含如下角色:
Context
Strategy
ConcreteStrategy
實作Strategy Pettern 這邊使用 Swift 實作一個簡單的 Stategy Pattern 例子。
首先我們有一個 Sequence
的 class
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class Sequence { private var numbers:[Int ] init (_ numbers :Int ...) { self .numbers = numbers } func addNumber (value :Int ) { self .numbers.append(value) } func compute () -> Int { return self .numbers.reduce(0 , {$0 + $1 }) } }
那麼假設我今天想要在這類別增加新的功能呢? 通常是直接修改 Sequence
來增加或者修改原有的演算法。那麼我們來試著加入第二個演算法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 class Sequence { enum ALGORITHM { case ADD ; case MULTIPLY ; } private var numbers:[Int ] init (_ numbers :Int ...) { self .numbers = numbers } func addNumber (value :Int ) { self .numbers.append(value) } func compute (algorithm :ALGORITHM ) -> Int { switch algorithm { case .ADD : return self .numbers.reduce(0 , {$0 + $1 }) case .MULTIPLY : return self .numbers.reduce(1 , {$0 * $1 }) } } }
但是今天當我們需要增加多個演算法,或者是當大家分工在實作不同演算法時,我們就會出現一個問題,我們必須頻繁的修改 Sequence
類別,且每次修改都必須針對 func compute
方法,這樣的話就破壞了所謂的 封閉開放原則 - 類別應該開放擴充方式且對修改封閉
。那麼我們該如何做呢 ?
首先我們定義 stategy
與 context
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 protocol Stategy { func execture (values :[Int ]) -> Int ; } class SumStrategy : Stategy { func execture (values :[Int ]) -> Int { return values.reduce(0 , {$0 + $1 }) } } class MultiplyStrategy : Stategy { func execture (values :[Int ]) -> Int { return values.reduce(1 , {$0 * $1 }) } }
接著我們修改原本的 Sequence
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class Sequence { private var numbers:[Int ] init (_ numbers :Int ...) { self .numbers = numbers } func addNumber (value :Int ) { self .numbers.append(value) } func compute (algorithm :Stategy ) -> Int { return algorithm.execture(values: self .numbers) } }
之後我們要對 Sequence
增加新的演算法,例如相減,我們只需要實作 SubtractionStrategy
即可,並且像下列的方式使用 :
1 2 3 4 5 6 7 8 let sequence = Sequence (1 , 2 , 3 , 4 )sequence.addNumber(value: 10 ) sequence.addNumber(value: 20 ) let sumStrategy = SumStrategy ();let multiplyStrategy = MultiplyStrategy ();sequence.compute(algorithm: sumStrategy) sequence.compute(algorithm: multiplyStrategy)