今日もゾーンにいました。こういう時こそ複雑で難しい部分をやるに限る。今日の作業の一つとして、前にMediatorで実装しかけていた部分をFacadeに変更した。もともとFacadeにするのもアリだろうなと思いつつ、Facadeのレイヤーが増えるのがイヤで同じレイヤーのオブジェクト同士で協調させることを考えていた。しかし、他でも似たような要求が増えてきたので、結局Facadeで行くことにした。ユーザーインターフェースをシンプルに改良するには、一連の処理をまとめてやってくれるクラスがあると便利なのだ。

きっかけになったのはこんなケースだ。
クラスAの関数fooが1つの整数引数をもつことを

A#foo(int)

のように書くことにする。また、GUIから引数valを渡してA#foo(int)を呼び出す。これは

GUI - [val] -> A#foo(int)

のように書くことにする。ここで、関数fooに渡す引数valについて次のような制約があるとする。

  • A#foo(int)に与える引数の符号が、別のクラスBのプロパティであるsignと同符号にしたい

これを実現するための方法としてすぐに思い付くのは

GUI - [B#sign * abs(val)] -> A#foo(int)

のようにGUIからB#signの値を調べてA#foo(int)に渡す値を変更する方法だろう。しかし、この方法では、制約条件が変更された時にGUI側にif文による分岐を追加することになる。これは、GUIとルールの結合が強すぎるので好ましくない設計だ。
オブジェクト指向では、条件分岐を多態性に置き換えるのが常套手段だ。今回は、

GUI - [val] -> Rule#before_foo(int) - [B#sign * abs(val)] -> A#foo(int)

のようにした。クラスRuleは、引数valに対して適当な処理をしてA#foo(int)に引きわたす。このようにすることで制約条件はRuleの中にカプセル化され、制約条件の変更や切替えにもRuleクラスの修正やRuleクラスのサブクラスを作ることで対応できる。GUIは制約条件を気にせず常にvalを渡せばよい。

RuleクラスはデザインパターンのFacadeかつStrategyになっている(のだと思う)。デザパタは勉強したけど、ちゃんと分かっている自信はないです。


午後には待ちに待ったテスト機の用意ができたので、来週からは実機で動作テストをする予定。