Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
8
Help us understand the problem. What is going on with this article?
@y-some

[iOS/Swift] アプリ開発の実務的アプローチで学ぶデザインパターン ~Strategy/State~

More than 1 year has passed since last update.

この記事シリーズは、iOS/Swiftエンジニアである執筆者個人が、
ごく普通のiOSアプリ開発でよくある状況
Swiftのコアライブラリやフレームワークで使われているパターン
着目してデザインパターンを学び直してみた記録です。

関連記事一覧
[iOS/Swift] アプリ開発の実務的アプローチで学ぶデザインパターン

Strategy/Stateパターン概要

  • 条件によって違う処理内容を外部クラスに追い出し、どのクラスを使うかを実行時に選択するパターンです。
  • 具体的には、switch文の「caseが多い/caseごとの処理内容が濃い」場合に、caseごとにクラスを分離させることが多いと思います。
  • 「ユニットテストしやすく」「拡張がしやすい(影響範囲を限定できる)」というメリットがあります。
  • GoFのデザインパターンでは振る舞いに関するパターンに分類されます。
  • StrategyとStateは設計としては同じで、作成側の意図が何にあるかの違いです(と私は解釈しています)。
    • Strategyは性質の違いによる振る舞いの切り替え
    • Stateは状態の変化による振る舞いの切り替え

Strategyパターンの使い所

  • switch文の caseが多い/caseごとの処理内容が濃い 場合

Stateパターンの使い所

私なりの見解では、普通のiOSアプリでは使いどころを見つけるのはなかなか難しいと思います。

一番利用したい場面は『データの「取得開始前」「取得中」「取得成功」「取得エラー」という状態の変化でViewを更新する』ですが、UIKitがそのような設計にマッチしないためです。

サンプルコード

Xcode 11.3 / Swift 5.1 です。
Playgroundにコピペすれば動作します。

Strategyパターンを適用しないサンプル

// 認証パラメータ
struct AuthInfo {
    var id = ""
    var password = ""
    var token = ""

    init(id: String, password: String) {
        self.id = id
        self.password = password
    }
    init(token: String) {
        self.token = token
    }
}

// 認証管理クラス
final class AuthManager {
    enum AuthType {
        case idPassword
        case token
    }

    static func authenticate(by type: AuthType, with authInfo: AuthInfo) {
        switch type {
        case .idPassword:
            if authInfo.id == "id" && authInfo.password == "password" {
                print("ID Password: auth success")
            } else {
                print("ID Password: invalid id or password")
            }
        case .token:
            if authInfo.token == "token" {
                print("Token: auth success")
            } else {
                print("Token: invalid token")
            }
        }
    }
}

AuthManager.authenticate(by: .idPassword, with: AuthInfo(id: "id", password: "password"))
// ID Password: auth success

AuthManager.authenticate(by: .token, with: AuthInfo(token: "token"))
// Token: auth success

Strategyパターンを適用したサンプル

// 認証パラメータ
struct AuthInfo {
    var id = ""
    var password = ""
    var token = ""

    init(id: String, password: String) {
        self.id = id
        self.password = password
    }
    init(token: String) {
        self.token = token
    }
}

// MARK: - Protocol
// 認証プロトコル
protocol AuthStrategy {
    func authenticate(_ authInfo: AuthInfo)
}

// MARK: - Context
// 認証を実行する役割
struct AuthContext {
    let strategy: AuthStrategy

    func execute(with authInfo: AuthInfo) {
        strategy.authenticate(authInfo)
    }
}

// MARK: - Concreate Strategies
// IDパスワード認証
struct IdPasswordAuthStrategy: AuthStrategy {
    func authenticate(_ authInfo: AuthInfo) {
        if authInfo.id == "id" && authInfo.password == "password" {
            print("ID Password: auth success")
        } else {
            print("ID Password: invalid id or password")
        }
    }
}
// トークン認証
struct TokenAuthStrategy: AuthStrategy {
    func authenticate(_ authInfo: AuthInfo) {
        if authInfo.token == "token" {
            print("Token: auth success")
        } else {
            print("Token: invalid token")
        }
    }
}

// MARK: - Usage
var context = AuthContext(strategy: IdPasswordAuthStrategy())
context.execute(with: AuthInfo(id: "id", password: "password"))
// ID Password: auth success

context = AuthContext(strategy: TokenAuthStrategy())
context.execute(with: AuthInfo(token: "token"))
// Token: auth success
8
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
y-some
Around 50のiOS Developerです。このサイトへの掲載内容はあくまで私個人の見解であり、所属企業における立場、戦略、意見を代表するものではありません。

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
8
Help us understand the problem. What is going on with this article?