この記事シリーズは、iOS/Swiftエンジニアである執筆者個人が、
ごく普通のiOSアプリ開発でよくある状況や
Swiftのコアライブラリやフレームワークで使われているパターンに
着目してデザインパターンを学び直してみた記録です。
関連記事一覧
[iOS/Swift] アプリ開発の実務的アプローチで学ぶデザインパターン
Chain Of Responsibilityパターン概要
- 全体を統率するクラスを作らず、個々のクラスが**責務を「たらい回し」**して、責務を果たせるクラスに行き当たった時点でそのクラスが処理を行います。
- GoFのデザインパターンでは振る舞いに関するパターンに分類されます。
使い所
- iOSエンジニアにとってはおなじみの、UIKitの「Responder Chain」という仕組みがChain Of Responsibilityパターンに則って構築されています。
Responder Chainとは?
UIResponderオブジェクトの繋がりのことで、この繋がりの順番にしたがって
touchイベントなどの処理ができるUIResponderオブジェクト(=first responder)を見つけて処理を行う仕組みです。
- アプリ開発での使い所は思い当たらなかったのですが、iOSフレークワーク内部で使われている仕組みであるわけですから、概念を理解しておいて損はないかと思います。
サンプルコード
Swiftバージョンは 5.1 です。
protocol Withdrawing {
// 引き出す
func withdraw(amount: Int) -> Bool
}
// 札束クラス
final class MoneyPile: Withdrawing {
// 額面
let value: Int
// 枚数
var quantity: Int
// 責務をたらい渡す次のオブジェクト
var next: Withdrawing?
init(value: Int, quantity: Int, next: Withdrawing?) {
self.value = value
self.quantity = quantity
self.next = next
}
func withdraw(amount: Int) -> Bool {
var amount = amount
func canTakeSomeBill(want: Int) -> Bool {
return (want / self.value) > 0
}
var quantity = self.quantity
while canTakeSomeBill(want: amount) {
if quantity == 0 {
break
}
amount -= self.value
quantity -= 1
}
guard amount > 0 else {
return true
}
if let next = self.next {
return next.withdraw(amount: amount)
}
return false
}
}
// ATMクラス
final class ATM: Withdrawing {
// $100の札束
private var hundred: Withdrawing
// $50の札束
private var fifty: Withdrawing
// $20の札束
private var twenty: Withdrawing
// $10の札束
private var ten: Withdrawing
private var startPile: Withdrawing {
return self.hundred
}
init(hundred: Withdrawing,
fifty: Withdrawing,
twenty: Withdrawing,
ten: Withdrawing) {
self.hundred = hundred
self.fifty = fifty
self.twenty = twenty
self.ten = ten
}
func withdraw(amount: Int) -> Bool {
return startPile.withdraw(amount: amount)
}
}
// Usage
// 札束オブジェクトを生成して $10 -> $20 -> $50 -> $100 と数珠つなぎにする
let ten = MoneyPile(value: 10, quantity: 6, next: nil)
let twenty = MoneyPile(value: 20, quantity: 2, next: ten)
let fifty = MoneyPile(value: 50, quantity: 2, next: twenty)
let hundred = MoneyPile(value: 100, quantity: 1, next: fifty)
// ATMオブジェクトを札束オブジェクトを格納して生成する
var atm = ATM(hundred: hundred, fifty: fifty, twenty: twenty, ten: ten)
// ATMには合計$300しか入っていないため$310は引き出せない
atm.withdraw(amount: 310) // false
// $300は引き出せる
atm.withdraw(amount: 100) // true
引用:
https://github.com/ochococo/Design-Patterns-In-Swift#-chain-of-responsibility