LoginSignup
1
2

More than 3 years have passed since last update.

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

Posted at

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

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

Commandパターン概要

  • Command=命令をオブジェクトとして扱うパターンです。
  • Commandオブジェクトは、「パラメータ」と「処理」をカプセル化したモノ。
  • GoFのデザインパターンでは振る舞いに関するパターンに分類されます。

使い所

  1. 並列処理を行いたいケース
  2. Queueing処理(Commandの待ち行列管理)を行いたいケース
  3. (DBを使わずに)ある時点の状態へのロールバックを行いたいケース
  4. Commandオブジェクトの生成元とは異なる場所でCommandを実行したいケース
  • 上記1、2を実現するための言語機能であるOperation(とOperationQueue)は、Commandパターンに則って構築されています。
  • したがってSwiftでは、Commandパターンのコードを自力で実装しなければならないケースは少なそうです。
  • とはいえ前提知識として、Commandパターンのコンセプトは理解しておいて損はないかと思います。

(ご参考)
【Swift】Grand Central Dispatch (GCD)とOperationQueue まとめ > Operation Queue

サンプルコード(Commandパターンの実装例)

Swiftバージョンは 5.1 です。

class Command {
    let receiver: Receiver

    init(receiver: Receiver) {
        self.receiver = receiver
    }

    func execute() {}
}

class HelloCommand: Command {
    override func execute() {
        receiver.action(message: "Hello")
    }
}

class WorldCommand: Command {
    override func execute() {
        receiver.action(message: "World")
    }
}

protocol Receiver {
    func action(message: String)
}

class PrintReceiver: Receiver {
    func action(message: String) {
        print(message)
    }
}

class Invoker {
    private var commands = [Command]()

    func addCommand(_ command: Command) {
        self.commands.append(command)
    }

    func execute() {
        for command in commands {
            command.execute()
        }
    }
}

let invoker = Invoker()
let receiver = PrintReceiver()
let hello = HelloCommand(receiver: receiver)
let world = WorldCommand(receiver: receiver)
invoker.addCommand(hello)
invoker.addCommand(world)

invoker.execute()

// 処理結果
// "Hello"
// "World"

引用元:
しめ鯖日記 - Swiftで学ぶデザインパターン22 (Commandパターン)

サンプルコード(Operationの実装例)

import Foundation
class MyCommand: Operation {
    var commandName: String
    var delay: Int

    init(commandName: String, delay: Int) {
        self.commandName = commandName
        self.delay = delay
    }

    override func main() {
        for _ in 0..<delay {
            sleep(1)
        }
        print(commandName)
    }
}

let operationQueue = OperationQueue()
// 最大同時実行数
operationQueue.maxConcurrentOperationCount = 3


let command1 = MyCommand(commandName: "command1", delay: 1)
let command2 = MyCommand(commandName: "command2", delay: 3)
let command3 = MyCommand(commandName: "command3", delay: 2)

operationQueue.addOperation(command1)
operationQueue.addOperation(command2)
operationQueue.addOperation(command3)

// 処理結果
// "command1"
// "command3"
// "command2"

OperationとOperationQueueを使ってみると、Commandパターンになっていることが理解できるかと思います。

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2