💭
マーティン・ファウラー氏のPassive Viewパターンを読み解いてSwiftで例を表現したい
はじめに
ここ数年のiOSアプリ開発でよく使われているMVPのPassive Viewパターンについて、原著のマーティン・ファウラー氏のブログ記事を振り返って読んで、念の為理解を深めてみようと思って書いてみました。
ただの感想文ですが、
マーティン氏の記事の例をSwiftで表現してみたら少しは分かりやすいかもしれないと思って載せています。
もし何か認識違いがあればコメントで指摘いただければ幸いです。
最初に私の結論
- Passive ViewはMVP特有のものではない
- MVCでも使える
- マーティン氏の説明でもControllerが使われており、そこはPresenterと読み替えても良さそう
- MVCでも使える
- Passive ViewはViewが受動的(Passive)で能動的ではない
- あくまでViewは受け身でありPresenterがViewに値をセットしたりする
- 自分で値をセットしたりしない
- あくまでViewは受け身でありPresenterがViewに値をセットしたりする
- ViewはUIイベントをPresenterに伝える
- Presenterにイベントを送信する
- ViewがPresenterのメソッドを呼び出す
- Presenterにイベントを送信する
あと、念の為
- Passive Viewの重要でないこと
- PresenterがViewをObserveするかどうかはあまり重要ではない
- 説明文には述べられていないが例ではPresenterがViewをObserveしている
- 説明にはないのでそこは必須じゃなくて良さそう
- 説明文には述べられていないが例ではPresenterがViewをObserveしている
- Swiftプログラミングだと当たり前だがそうでないこと
- weakだとかOptionalだとかはあくまでSwiftの都合であって原著ではそこらへんは記載していない
- PresenterがViewをObserveするかどうかはあまり重要ではない
本題: マーティン・ファウラーのPassive View
- 背景
- マーティン氏は2002年にエンタープライズアプリケーションアーキテクチャパターンという書籍を出した
-
その本だけでは説明しきれていないパターンについてをブログに引き続き書いていた
- Passive Viewは2006年7月18日に記事にしたもの
-
その本だけでは説明しきれていないパターンについてをブログに引き続き書いていた
- マーティン氏は2002年にエンタープライズアプリケーションアーキテクチャパターンという書籍を出した
- 構成
- マーティン氏のPassive View記事の構成は3つに別れています
- 序文っぽいもの
- How It Works
- When to Use It
- マーティン氏のPassive View記事の構成は3つに別れています
箇条書きで雑にまとめていきます
序文っぽいもの
- リッチクライアントシステム(クライアント環境で動くアプリ、WindowsアプリとかiOSアプリとか)はテストが複雑
- なぜなら
- フレームワークがテストを念頭に置いて構築されていないから
- なぜなら
- Passive View
- やること
- ユーザイベントへの応答を処理する
- Viewの更新を行うためのコントローラを使用する
- (訳注: MVCのときはコントローラを利用するという意味でMVPのときはPresenterがやることでしょう)
- View(UIコンポーネント)の動作を最小限に抑える
- やること
> How It Works
- Passive ViewというのはMVCやMVPを使う場合のバリエーション
- (訳注: MVPでPassive Viewを使ったり、MVCでPassive Viewを使うということでしょう)
- UIというものは2つに分割される
- 2つ
- 表示を処理するビュー
- ユーザイベント(ジェスチャーなど)に応答するコントローラ
- 2つ
- 特徴
- Viewは完全に受け身(Passive)
- Modelから自分自身を更新する責任がない
- Viewのロジックはコントローラの中にある
- ViewとModel間には依存関係がない
- assessmentウィンドウの例
- (訳注: assessmentウィンドウというViewがあると思うのがよろしいかと)
- ユーザ操作をすぐにコントローラに伝える
- コントローラはModelを更新する
- Modelからビューを再読込する
- ウィジェット(訳注: Viewのことをウィジェットって表現したりUIコンポーネントって言ったりしてる?)を更新
- コントローラはModelを更新する
- 目的
- 主に自動テスト
- コントローラのテストでは
- Viewのテストダブル(スタブ/モック)を利用し、UIフレームワークとのインタラクションを必要としない
- 中間ゲートウェイをセットアップする
- (訳注: それは詳細をもっと示してくれ)
- コントローラのテストでは
- 主に自動テスト
例
マーティン氏のブログからシーケンス図を引用
シーケンスを雑に日本語で順に表現すると次のようになる感じでしょうか
- TextFieldに50が入力される
- textが変更されるとControllerが検知
- Controllerがtextを取得
- 50がModel側に渡される
- ControllerはloadView
- Model(:Reading)から50取得
- viewへ50をset
- Modelからvarianceを取得(varianceってのは50の場合に変わる値?)
- varianceなtextFieldにvarianceの値をset
- ModelからvarianceなCategoryを取得
- varianceなtextFieldへCategoryを解釈しredをセットする
上記シーケンス図から簡易的にSwiftで表現してみます。
class AssesmentWindow {
class Field {
var text: Text // getter / setter
}
var actualField: Field
var varianceField: Field
}
class AssesmentController {
private let view: AssesMentWindow
private let record: AssesmentRecord
func observe() {
// viewの値がかわったらloadViewが動くようにする
observe(view) { $0
record.actual = $0
loadView()
}
}
private func loadView() {
// get actual
let value = record.actual
// set text
view.actualField.text.value = value
// get variance
let variance = record.variance
// set text
view.varianceField.text.value = variance
// get variance category
let category = record.varianceCategory
// set text color
// 以下プレゼンテーションロジック部分
let color = ...
switch category {
case ...: //
color = .red // categoryからredを
...
}
view.varianceField.text.color = color
}
}
class AssesmentRecord {
var actual: Int
private(set) var variance: Int
private(set) var varinaceCategory: Category
}
> When to Use It
- Passive Viewの理由
- Viewをコントローラの矮小された奴隷にすることでViewをテストしないことによるリスクはほとんどなくなる
- (訳注:
the view reduced to a dumb slave of the controller,
の表現わかりづらすぎ。深く考えたくない)
- (訳注:
- テストにおいてPassive Viewが一番優れてるわけじゃない
- Viewをコントローラの矮小された奴隷にすることでViewをテストしないことによるリスクはほとんどなくなる
Passive View記事自体の感想
記事の中ではView、UIコンポーネント、ウィジェットなどの用語がぶれているのかあえて別々な言い方をしたいのかが正直私にはわからないなというのが読むたびに思いますね。
表現として、the view reduced to a dumb slave of the controller
など表現が訳しづらいがニュアンスは分かるようなのがあります。言いたいことは分かるが、すごく日本語として汚くないように訳すことは難しそうですね。
さらに中間ゲートウェイをつかったテスト手法部分もあるんですが、それについてはあまり深追いしても意味が無さそうなんで除外しています。
Discussion