📖
【学習備忘録】(Swift)Strategyパターン
はじめに
デザインパターンについて、ViewControllerに全て詰め込んでコードを書く方法から脱却したい、そしてTDD(テスト駆動開発)をしたいと思い、まずはデザインパターンの学習をしています。
Strategyパターンについて学習し、下の参考リンクの動画内のコードを写経しました。
Strategyパターンとは
・Strategyという英単語は、戦略という意味になります。プログラミングの場合はアルゴリズムと考えていいみたいです。
・どんなプログラムも問題を解くために書かれています。問題を解くために特定のアルゴリズムが実装されています。Strategyパターンは、アルゴリズムを実装した部分をごっそりと交換できる方式です。
・GoFのデザインパターンでは、振る舞いに関するデザインパターンに分類されます。
下のコードでは、じゃんけんに関する戦略を切り替えることができる実装となっています。
サンプルコード
・ViewControllerがスッキリしていることに感動しました。
・実際にクラス図を書いたり、コードの流れを追うとより理解が深まりました。
・Game型のPlayerのインスタンス生成時に引数(strategy)を切り替えることで戦略を変更することができます。
class ViewController: UIViewController {
let game = Game()
override func viewDidLoad() {
super.viewDidLoad()
game.run()
}
}
enum Result {
case win
case lose
case draw
}
enum Hand {
case guu
case cho
case paa
var name: String {
switch self {
case .guu:
return "グー"
case .cho:
return "チョキ"
case .paa:
return "パー"
}
}
func fight(hand: Hand) -> Result {
switch (self, hand) {
case (.guu, .guu), (.cho, .cho), (.paa, .paa):
return .draw
case (.guu, .cho), (.cho, .paa), (.paa, .guu):
return .win
case (.guu, .paa), (.cho, .guu), (.paa, .cho):
return .lose
}
}
static func random() -> Hand {
let hands: [Hand] = [.guu, .cho, .paa]
let index = Int.random(in: 0..<hands.count)
return hands[index]
}
}
protocol Strategy {
func nextHand() -> Hand
func study(win: Bool)
}
class WiningStrategy: Strategy {
private var won = false
private var prevHand: Hand?
func nextHand() -> Hand {
if won {
return prevHand!
} else {
prevHand = Hand.random()
return prevHand!
}
}
func study(win: Bool) {
won = win
}
}
class GuuStrategy: Strategy {
func nextHand() -> Hand {
return .guu
}
func study(win: Bool) {}
}
class ChoStrategy: Strategy {
func nextHand() -> Hand {
return .cho
}
func study(win: Bool) {}
}
class RandomStrategy: Strategy {
func nextHand() -> Hand {
return Hand.random()
}
func study(win: Bool) {}
}
class Player {
let name: String
let strategy: Strategy
private var winCount = 0
private var loseCount = 0
private var gameCount = 0
init(name: String, strategy: Strategy) {
self.name = name
self.strategy = strategy
}
func nextHand() -> Hand {
strategy.nextHand()
}
func win() {
strategy.study(win: true)
winCount += 1
gameCount += 1
}
func lose() {
strategy.study(win: false)
loseCount += 1
gameCount += 1
}
func even() {
gameCount += 1
}
var result: String {
"[\(name) : \(gameCount) games, \(winCount) win, \(loseCount) lose]"
}
}
class Game {
func run() {
let player1 = Player(name: "taro", strategy: ChoStrategy())
let player2 = Player(name: "jiro", strategy: GuuStrategy())
(0..<100).forEach { _ in
let nextHand1 = player1.nextHand()
let nextHand2 = player2.nextHand()
switch nextHand1.fight(hand: nextHand2) {
case .win:
print("Winner: \(player1.name)")
player1.win()
player2.lose()
case .lose:
print("Winner: \(player2.name)")
player1.lose()
player2.win()
case .draw:
print("Draw...")
player1.even()
player2.even()
}
}
print("Total result:")
print(player1.result)
print(player2.result)
}
}
GitHub
参考にしたもの
1.[ライブ] Swiftでデザインパターン使ってみる(Adapter, Builder, Strategy)
2.デザインパターン ~Strategy~
さいごに
写経し、データの流れを追うことでより理解が深まりました。また、書籍のコードやネットのコードを理解する、そして他人のコードを読めるようになるにも、デザインパターンを学習することで助けになってくれると感じました。
間違いや認識違いがあれば指摘いただければ幸いです。
Discussion