這些天Stone City決定是時候開始向外拓展,他們希望能夠先排除機器人去清理外界的怪獸,在清理之後才能開始將城市向外拓展。
冒險者A
Stone City的市長告訴我們說,他們很久以前就有嘗試過要派出機器人出去探險,但是卻失敗了,而失敗後因為經費的問題一直遲遲沒有再次嘗試。
但因為有派出去的經驗,他們發現如果機器人只有「普通攻擊」的功能,很容易就會被怪獸打壞,還需要有一些特殊的攻擊方法。
比如:撿起身邊的石頭進行拋射、快速奔跑衝撞、噴水等攻擊方式。
1 2 3 4 5 6 7 8 9 10 11 |
class AdventureA { private let name:String init(adventureName:String) { name = adventureName } func attack() { print("勇者 \(name) 進行了 普通攻擊") } } |
於是我們很快的進行了系統的修改:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
class AdventureA { private let name:String init(adventureName:String) { name = adventureName } func attack() { print("冒險者 \(name) 進行了 普通攻擊") } func rockAttack() { print("冒險者 \(name) 進行了 石頭拋射攻擊") } func waterAttack() { print("冒險者 \(name) 進行了 噴水攻擊") } func rushAttack() { print("冒險者 \(name) 進行了 衝撞攻擊") } } |
有沒有一個更好的方法來封裝這些attack策略呢?
策略模式(Strategy Pattern)
- 什麼時候用:如果在一個系統中有許多類,而他們之間的區別只在於他們的行為。
完成一項任務,往往可以有多種不同的方式,而每一種方式都可以稱為是一種策略,我們可以根據環境或者條件的不同而選擇不同的策略來完成該任務。
在策略模式中,可擴展的類被稱為上下文類(context class)。環境類並不直接實現某個功能,而是委託遵循策略協議的類去實現。
策略模式不需要指名如何選區某個具體的策略,最常見的做法是讓調用組件去做選擇。
我們將幾種特殊的攻擊模式包裝成一個策略類,並且通過protocol Strategy規定要實現一個attack方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
protocol Strategy { func attack() -> String } class RushStrategy:Strategy { func attack() -> String { return "衝撞" } } class RockStrategy:Strategy { func attack() -> String { return "石頭拋射" } } class WaterStrategy:Strategy { func attack() -> String { return "噴水" } } |
在實現策略模式時,主要目標是定義一個無需修改或者繼承的環境類。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
class AdventureB { private let name:String init(name:String) { self.name = name } func attackWith(strategy:Strategy?) { if strategy != nil { let way = strategy!.attack() print("冒險者 \(name) 進行了 \(way) 攻擊") } else { print("冒險者 \(name) 進行了 普通 攻擊") } } } |
所以我們通過調用組件來創建策略實現類的實例,並將策略傳給環境類的方式:
1 2 3 4 5 6 7 8 |
let adventureB = AdventureB(name: "Adventure B") // 不是用策略 adventureB.attackWith(strategy: nil) // 使用rock Strategy let rockStrategy = RockStrategy() adventureB.attackWith(strategy: rockStrategy) |
輸出結果:
1 2 |
冒險者 Adventure B 進行了 普通 攻擊 冒險者 Adventure B 進行了 石頭拋射 攻擊 |
iOS App開發中的例子
Cocoa框架中對策略模式的使用非常廣泛,用來支持在不修改和繼承框架類的情況對其進行擴展。
比如UI組件的策略,一個典型的例子就是UITableView依賴一個遵循UITableViewDataSource協議的類,去實現相關策略並提供數據。
好的,冒險過後可以到github上看這次的策略模式的例子。