はじめに
これまで単発のパターンで例を作成していたが、似たようなパターンがあってどう使い分ければ良いのか理解しないと、いざというときに使えないので、今回はまとめて例を考えてみる。
状態管理のパターンと、関連するパターンとしてMediatorパターンを例に挙げる。
Observerパターン
「観察者」というパターンだが、実際は「通知」されるのを受動的に待つパターンです。
ConcreteObserverや、ConcreteSubjectの増減に柔軟に対応したいときに使うパターンです。
例:
桜木花道(ConcreteSubject)のシュート2万本の練習は安西先生(ConcreteObserver)に通知する必要がある。
安西先生はその通知を受けたら、次の秘密特訓メニューを考えます(updateメソッド実装)。
安西先生だけでなく、田岡先生(陵南高校バスケ部監督が湘北コーチになったときなど)にも通知する必要があったり、
花道だけでなく、三井も練習に加わりたいときなどに、
柔軟に対応できるパターン例。
嬉しさ:
・花道と先生の依存関係が緩くなっている。
→ 選手と先生を簡単に置き換えることができる。
→ 安西先生が田岡先生になったとしても、花道が才能開花していたかというと微妙だが、それは漫画の話なので、考えないことにする。
注意:
先生(Observer)同士はお互いの存在を知らないので、
同じような特訓メニューを組んでしまうかもしれない。
通知後のアクションに依存関係や、副作用があるときは使わないほうが良いかもしれない。
Mementパターン
Memento とは、英語で「記念品」「形見」を意味する単語です。
一度変化してしまったインスタンスを、「少し前の状態に戻したい」「ある時点の状態に戻したい」というときに使うパターン。
少し前の状態に戻すための情報が、実装の詳細に関わることであり、公開してしまうとカプセル化を破壊してしまうときに使う。
例:
パワプロのサクセスで、良い成績を残していたときにダイジョーブ博士が現れたときに、
一気にステータスが下がる可能性があるので、セーブしておきたいことがあります。
(※筆者は大分昔のパワプロしかやってないんですが、最近はセーブしてやり直しはできないようになってますよね、多分。)
プレイヤーは、パワプロをプレイしているプレイヤーです。
練習や試合を重ねて、ステータス(ミートAとか、パワーAとかだけでなく、どれくらい練習したかとか、プレイヤーが知らなくても良い詳細ステータス含む)が良い感じになってきたら、プレイヤーはcreateMementoで、今のステータスのスナップショットを取っておきます。(昔プレステでやってたときはメモリーカードに保存してました、懐かしい)
ダイジョーブ博士が現れて、手術に失敗したら、restoreMementoを呼び出してスナップショットのステータスに復活させます。
嬉しさ:
プレイヤーが知らなくても良い情報は知らなくとも、少し前の状態に戻すことができる。(カプセル化)
注意:
Mementoの管理コストに注意する。
プレイヤーが頻繁にセーブしたいときや、保持するステータスが膨大な場合などは、管理(メモリ消費、オブジェクト削除等)にコストがかかるので使わないほうが良いかもしれない。
Stateパターン
State パターンとは、 モノではなく、「状態」をクラスとして表現するパターンです。
例:
寄生獣の新一とミギーを例にして考えました。
一回新一が大怪我したときに、ミギーの体の一部を新一に移植しましたよね、そのあとはミギーが眠ってしまう頻度が増えたと思います。
ミギーが眠っている間は普通の右手としてしか使えないです。
状態に依存した振る舞いをするメソッドを持つ「state」クラスを継承して「ミギー」と、「人間右手」クラスを置いてます。
「ミギー」だと、会話ができますが、「人間右手」だと、会話はできませんよね。
「ミギー」だと、変形して相手を食べることができますが、「人間右手」だと、物理的なパンチしかできません。
この例だとあんまり状態によってクラスが増えていかないので、適切な例ではなかったかもしれませんが、眠たいときのミギーと、元気なときのミギーの振る舞いを変えたくなったときも、簡単に追加することができます。
ここでの状態遷移は数時間起きにChangeStateを外部から設定される想定です。
嬉しさ:
状態遷移によって振る舞いが変わる部分を局所化し、追加・削除が容易。
注意:
状態遷移を誰が定義するか。
書籍の例題だとConcreteStateクラスから状態遷移をしていました。
単純な状態遷移だとそれでも良いかもしれませんが、
各クラスでいろんな状態遷移を実装するのは微妙だと思いました。
Mediatorパターンが適用して、調停するなどができたら良いのかもしれません。
Mediatorパターン
Mediator とは、英語で「仲裁人、調停者」を意味する単語です。 Mediator パターンとは、多数のオブジェクトの間の調整を行いながら処理をすすめる必要が ある場合に利用すると威力を発揮するパターンです。
例:
このパターンの例はおもしろいのが思いつきませんでした。
Mediator:「仲裁人、調停者」、Colleage:「同僚」という意味なので、
単純に僕らの職場をイメージしました。
上司と社員がいて、具体的な上司は社員Aと社員Bを保持していて、
社員からの面談を受けて他の社員と調停しています。
ここではみんなとの面談結果を上司Aが判断して、各社員の「役割変更」を呼び出します。
これによって、社員間の依存関係を少なくすることができます。
嬉しさ:
- 社員クラス間(Colleageクラス間)の結合度を低くできる。
- 社員クラス間の相互作用、制御を上司クラス(Mediateorクラス)に集中することができる。
注意:
上司や社員が変わらない場合はこのパターンは不要かもしれない。
まとめ
Stateパターンだけでなく、Mediatorパターンを組み合わせて、状態遷移をひとつにまとめるなど、複数のパターンを使って最適な設計をしていく必要がある。
状態遷移は大体必要になるので、stateパターンが使えるか、
何か通知が必要になったときにObserverパターンが使えるか、
スナップショットを取りたいとき、Undoをする必要があるときにMementoパターンが使えるか、
また、複数の機能の調停などを行いたいときにMediatorパターンが使えるか、
を設計時に検討していきたいと思います。
感覚としては、stateパターンは使いやすそうですが、
その他はほんとに使ってメリットがあるか、使わないほうがシンプルにならないか?とか考えて慎重に使っていきたいと思いました。