Powered By Blogger

2013年11月19日火曜日

デザインパターンはオブジェクト指向設計が出来ない人のためのソリューション

http://itpro.nikkeibp.co.jp/article/COLUMN/20051123/225074/

抜粋始め^^^^^^^^^^^^^^^^^)

 今回は、パターンを1つだけ紹介します。「Mediatorパターン」です。GoF本では、それぞれのパターンの「目的]「背景」「効果」などが明示されています。私も、ちょっと真似をしてみましょう。複数のオブジェクトを組み合わせてプログラムの機能を実現するという目的において、オブジェクト間の関連がゴチャゴチャになってしまうという背景(問題)があり、Mediatorパターンの採用によって関連をキレイに整理できるという効果があります。説明だけでは、何のことだかわからないと思いますので、具体例をお見せしましょう。

図1[拡大表示](1)をご覧ください。これは、UML(Unified Modeling Language、ユーエムエル)と呼ばれる表記法で記述されたプログラムの設計図です。UMLでは、四角形の中に下線付きで名前を書いてオブジェクトを表し、関連のあるオブジェクトを矢印で結んで示します。ここで関連があるとは、他のオブジェクトの持つメソッドを呼び出しているという意味です。

 見ての通り4つのオブジェクトA~Cが、それぞれ他の3つのオブジェクトと関連を持っています。このまま無事に動作しているなら問題ないでしょう。しかし、もしも1つのオブジェクトの内容を改造したらどうなるでしょうか? 他のすべてのオブジェクトに影響を及ぼしてしまいます。新たなオブジェクトを追加する場合も、それと関連する複数のオブジェクトに何らかの改造が必要になるはずです。プログラムを改造したら、テストしなければなりません。たった1つのオブジェクトを改造や追加したことで、プログラムの多くの部分をテストし直さなければならないのです。これは、あまりにも面倒なことでしょう。

 問題の原因は、オブジェクト間の関連が複雑過ぎることです。そこで、他のオブジェクトの調停者となるオブジェクトMを追加してみましょう(図1[拡大表示](2))。オブジェクトA~Dは、オブジェクトMを仲介して他のオブジェクトと関連付けられることになります。もしも、オブジェクトAを改造したとしても、影響を及ぼすのはオブジェクトMだけで済みます。オブジェクトMの中で、オブジェクトAの改造を吸収してしまえば、オブジェクトB~Dの改造は不要です。これがMediatorパターンです。

 オブジェクト指向プログラミングの成功の秘訣として「できるだけオブジェクト間の関連を少なくする」ということがあります。Mediatorパターンを採用することで、オブジェクト間の関連の数を少なくできます。図1[拡大表示](1)では、6本の線がありましたが、図1[拡大表示](2)では4本になっています。新たなオブジェクトを追加する場合も、線が1本増えるだけで済みます。

 私は、Mediatorパターンを知って大いに感動しました。ただし、パターン自体に感動したわけではありません。GoFデザインパターンの中に、オブジェクト指向プログラミングを効果的に実践するヒントがあることに気付いて感動したのです。いずれは自分自身でオリジナルのパターンを考えるべきですが、その前に、お手本となるGoFデザインパターンを知っておきましょう。23種類のすべてのパターンがすぐに役立つとは限りませんが、その中のいくつかは、きっと皆さんのツボにはまって「ピピッ!」と感じさせてくれるはずです。

抜粋終わり^^^^^^^^^^^^^^^^^)

単に私がデザインパターンが嫌いというだけなのですが、、、、上の話、単にオブジェクトの実装がおかしいだけなのではないでしょうか。そもそも、オブジェクト(クラス)を考える時、自分で考えられるオブジェクトを想像しながら作ったはず。上記の調停者は元々の考えには存在しないクラスであり、実装の都合上で考えられた辻褄合わせのオブジェクトです。このようなオブジェクト図を見て、プロジェクトメンバー以外の誰一人としてこのシステムを理解できなくなるのは自明です。この調停者は何を担うのでしょうか。呼び出し関係を調停する?そんな必要があるのでしょうか。もしあるのであれば、上記のオブジェクトAからDの作り込みがおかしいとしか言えないのではないでしょうか。そのように気づいた場合は、即座にオブジェクトAからオブジェクトDを作り直すべきでしょう。そのためにオブジェクト指向を行っているのですから。オブジェクト指向の基本に立ち返れば、オブジェクトMなどという調停者オブジェクトは不要でしょう。

 大体、複雑になったから、グローバルなクラスを作ってそこがそれぞれを呼び出せば良いなんて誰が考えるんだろう。オブジェクトAからDは単なる関数の集まりで、クラスでも何でも無いのではないだろうか。つまり、調停者というオブジェクトのサブルーチンというわけ。
 こうなるとカプセル化もできないし。それに上記のように一つのオブジェクトを変更したら、オブジェクトMを変更しなければならなくなり、オブジェクトMは全てのオブジェクトを制御するので、その論理は非常に複雑になっており、その影響で他のオブジェクトとのインタフェースを再作成する必要がでるのであれば、直接呼んでいた方が修正量が少ないのではないでしょうか。オブジェクトA、オブジェクトD、オブジェクトMを修正するより、オブジェクトAとオブジェクトDを修正した方が簡単でしょ。なぜインタフェースを二重化して、ソースコードを分割して論理を判りにくくしているのかがよく分かりません。筆者の言う「ピピッ!」は全く感じませんね、私には。
 それに、「いずれは自分自身でオリジナルのパターンを考えるべきですが」とありますが、同じクラスはそうそう出てこないでしょう。また、クラスが再利用できるなんて言っていますが、私の経験上では、ほぼ不可能です。クラスの一部はコピーできても、クラス全体をコピーできることはまずありません。例えば従業員クラスがあったとして、最初に開発した会社Aでは職歴に支社コードを関連づけていないとダメだとしましょう。後に開発した別の会社Bのシステムでは支社コードと関連づけてはいけないとしましょう。では支社コードを使わなければいいので、従業員クラスをそのままB社に適用するかと言えば、Noです。従業員クラスをコピーした後、支社コードの論理と変数を削除したものを使います。なぜなら、新しい従業員クラスでは支社コードを関連づける論理が付いているのは一般的でなく判りにくいからです。それで、元の従業員クラスを派生クラスにして、新しい従業員クラスを親クラスにしますか。それをA社のシステムに適用できますか?いまさら出来ないでしょう。また、自社のこれからの開発の為にA社用従業員クラスとB社用従業員クラスを作り、親クラスの従業員クラスを作りますか?しないでしょう。なぜなら、もっと規模の小さいシステムの仕事が来たら、従業員クラス自体が単なるDBアクセスルーチンになるかもしれないのですから。例えば同じクラスを何度も使える仕事が来るということは、パッケージ化できるということです。逆に、パッケージ化できないのなら、体制が問題でしょう。

システムがコピーできるとか再利用できるとか考えるのではなくて、そのシステムに最適なオブジェクトを構築してメンテナンスを楽にする。という方がオブジェクト指向なのではないでしょうか。再利用できるなんていうのは、経営者にオブジェクト指向を使わせるための方便でしょう。再利用は一部のソースコードだけですから、それはオブジェクト指向でなくても使えます。まあ、オブジェクト指向の方が取り出しやすいのは確かですが。 ここにデザインパターンは関係ありません。 デザインパターンは何も解決しません。

デザインパターンはオブジェクト指向設計が出来ない人のための偽オブジェクト指向システムへの解決策だと思います。

0 件のコメント:

コメントを投稿