📖

【学習備忘録】(Swift)Strategyパターン

2022/05/16に公開

はじめに

デザインパターンについて、ViewControllerに全て詰め込んでコードを書く方法から脱却したい、そしてTDD(テスト駆動開発)をしたいと思い、まずはデザインパターンの学習をしています。
Strategyパターンについて学習し、下の参考リンクの動画内のコードを写経しました。

Strategyパターンとは

・Strategyという英単語は、戦略という意味になります。プログラミングの場合はアルゴリズムと考えていいみたいです。
・どんなプログラムも問題を解くために書かれています。問題を解くために特定のアルゴリズムが実装されています。Strategyパターンは、アルゴリズムを実装した部分をごっそりと交換できる方式です。
・GoFのデザインパターンでは、振る舞いに関するデザインパターンに分類されます。

引用:デザインパターン ~Strategy~

下のコードでは、じゃんけんに関する戦略を切り替えることができる実装となっています。

サンプルコード

・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

https://github.com/MasakatsuTagishi/Practice-StrategyPattern

参考にしたもの

1.[ライブ] Swiftでデザインパターン使ってみる(Adapter, Builder, Strategy)

https://www.youtube.com/watch?v=RU_jsa1MmSk&t=3578s

2.デザインパターン ~Strategy~

https://qiita.com/i-tanaka730/items/4d00c884b7ce1594f42a

さいごに

写経し、データの流れを追うことでより理解が深まりました。また、書籍のコードやネットのコードを理解する、そして他人のコードを読めるようになるにも、デザインパターンを学習することで助けになってくれると感じました。
間違いや認識違いがあれば指摘いただければ幸いです。

Discussion