これは、クライアントに、クライアントが本来依存しないメソッドへの依存性を強制してはならないという原則です。
詳しくお話ししてみましょう。
コンテンツ
コミュニケーションの分離
上司や先生など目上の人と話すときと、家族や友人など親しい人と話すとき、あるいは恋人や配偶者などさらに親しい人と話すとき。同じことを話すのでも、相手によって話し方が違いますよね。
話し方というのは、人間同士のコミュニケーションのためのインターフェイスです。
あなたという一人の人間が、相手によって使い分けるための、複数のインターフェイスを持っているわけです。
相手によって話し方が違うということは、相手によって違うインターフェイスを使い分けているということです。
インターフェイスは、それぞれ独立していますので、変更の影響を受けません。
変更の影響を受けない?どういうことでしょう。
例えば、人事異動によって上司が変わったとします。
新しい上司は、前の上司よりもかなり礼儀に厳しい人で、以前とは比べ物にならないくらい、話し方に気をつけなければなりません。
あなたの上司に対するインターフェイスは、このことで変更を余儀なくされます。
でも、そのせいで、家族との話し方まで変わったりはしませんよね。
あなたの、それぞれに対するインターフェイスが分離されているからです。
人間というのは、なんて柔軟にできているのでしょう。
道具のインターフェイス
これに対して、人間が作った道具には、それほど柔軟でないものがけっこうあります。例えば、お財布。
お財布というものは、もともとは、単にお金を入れるためだけのものですよね。
でも、世の中にカードというものが普及したことにより、たいていのお財布は、カード入れを備えるようになりました。
高機能なお財布ほど、たくさんのカード入れを持っています。
すごいのになると、クレジットカードやキャッシュカードを入れる場所の他、免許を入れる場所、定期を入れる場所など、いちいち専用のぴったりサイズの入れ場所が用意されてたりします。
それぞれの入れ場所は、ひとつひとつが、対応するカードに対するインターフェイスです。
- それぞれのカードにぴったりのサイズ
- 必要なものについては、入れたままでも見えるように透明になっていること
- よく取り出すものについては、取り出しやすいようにスリットが入っていること
たくさんのポケットは便利ではあるのですが、これは肥大化したインターフェイスです。
車や自転車で通う人は、定期を入れるところは使わないですよね。
また、クレジットカードやキャッシュカードを持ち歩かない人は、それらの入れ場所は使いません。
免許を持っていない人は、免許を入れる場所は使いません。
これらの人にとっては、そんなインターフェイスは必要ないのです。
それに、もしクレジットカードのサイズが少しでも大きく変更されたら、それだけでお財布が使い物にならなくなってしまいます。
カードや免許や定期のどれか一つのサイズが変わっただけで、お財布を丸ごと買い直さなければなりません。
お金を入れるところも何もかもが、役に立たなくなってしまうのです。
これは、一つのインターフェイスの変更が、他のインターフェイスに影響してしまう例です。
道具というのは、長い目で見ると、多機能なものより単機能なものの方がいいということですね。
この例のカードやお金は、持ち歩きやすくするために、お財布を利用します。
お財布を利用する立場ですので、カードはお財布のクライアントであるといえます。
お財布は、収納するという機能を提供する、サーバです。
ここで、冒頭の原則の内容を思い出して下さい。
クライアントに、クライアントが本来依存しないメソッドへの依存性を強制してはならない
これを今回の例に当てはめると、
「(お財布は) カードやお金に、それぞれ自分自身のもの以外のポケットに対して依存させてはならない」
ということになります。
この場合の「依存している」とはどういうことかというと、他のもののポケットが使えなくなったときに、財布全体が使い物にならなくなることで、自分のポケットまで使えなくなるという影響を受けることです。
高機能財布のなかには、それぞれの入れ場所が、べつべつに取り外せるようになっているものもあります。
そういうものは、使えなくなったところだけを取り外して、お財布自体は使い続けることができますね。
これなら、ちゃんとインターフェイスが分離されているといえます。
このように、インターフェイスはそれを使うクライアントによって、分離されているべきなのです。
これが、インターフェイス分離の原則です。
原則の関連
ちょっと振り返ってみてください。あなたが上司に対する話し方を変えなかればならなかったのは、上司が変わったことが原因でした。
また、お財布が使えなくなったのは、カードが変わったせいでした。
つまり、ここでインターフェイスは、あなたやお財布という下位モジュール (サーバオブジェクト) の都合ではなく、上司やカードという上位モジュール (クライアントオブジェクト) の都合によって変更されたのです。
インターフェイスは、サーバー側ではなく、クライアント側の都合によって変更されることがよくあります。
このことを、依存関係逆転の法則と関連づけて考えてみて下さい。
依存関係逆転の法則のお話に出てきた上位のモジュールは、たいてい利用する側、つまりクライアントです。
下位のモジュールは、たいてい利用される側、つまりサーバになります。
ヒトのコミュニケーションの例のように、インターフェイスが十分に分離されている場合、依存関係は逆転します。
サービスはサーバからクライアントへ提供され、依存関係はそれとは逆に、クライアントに対してサーバが依存します。
こうなっていれば、変更の影響を最小限に食い止めることができる、強固なシステムになります。
財布の例のように、インターフェイスが十分に分離されていない場合、依存関係は逆転せず、サービスを提供するサーバ側に対して、クライアントが依存することになります。
こうなっていると、変更の影響をシステム全体に伝播しがちな、脆弱なシステムになります。
依存関係を逆転させるためには、インターフェイスの分離は欠かせません。
このように、原則もパターンに似て、有機的に結びついているのです。
実装にあてはめてみる
インターフェイスの肥大化の問題は、プログラムでは継承階層のあり方にも影響します。継承階層の上位にあるクラスが、一部のクライアントしか利用しないようなメソッドを持っていると、全てのサブクラスがそれを実装しなければならなくなります。
あるサブクラスではそのメソッドを実際に使用するでしょうが、他のサブクラスでは、それは使わないメソッドになってしまうでしょう。
そういったサブクラスでは、そのメソッドをサポートしないというような例外を投げるか、何もしないでリターンすることになります。
これはインターフェイスの退化であり、潜在的にリスコフの置換原則に違反することになります。
こうなっていると、実際にメソッドを使用しているサブクラスの変更によって、メソッドのインターフェイスが変わってしまった場合に大変なことになります。
上位クラスに変更が及ぶのはもちろん、全てのサブクラスにまで、変更が及んでしまうのです。
全てのクラスが、そのメソッドを実装しているのですから。
全く無関係なクラスに影響が波及していく、悪夢のような状況です。
ところで、インターフェイスがクライアントごとに分離されていなければならないということは、それぞれのインターフェイスの仕様は、クライアントの都合によって決まるということを示唆しています。
これも、依存関係逆転の法則と矛盾しない方針ですね。
さて、インターフェイスを分離して、サーバがこれを実装するという方針を実現するには、主に2つの方法が考えられます。
ひとつは、アダプタパターンを利用した、委譲による実現方法です。
もうひとつは、多重継承による実現方法です。
アダプタパターンは、デザインパターンのひとつですが、これについてはおいおいお話ししたいと思います。
委譲による方法では、アダプタオブジェクトのためのクラスを大量に作成しなければならないかもしれません。
また、いちいちアダプタオブジェクトを生成しなければならないことや、委譲によるオーバーヘッドが問題になることがあるかもしれません。
そういったことが問題になる場合は、多重継承の戦略を採用することになるでしょう。
多重継承では、アダプタオブジェクトが必要ない分、クラス数を抑えることができ、設計もよりスマートになります。
単一継承の言語を使用するなら、単にインターフェイスをインプリメントすることで実現することができます。
オススメ
「問題のあるサンプル設計を元に、どこに問題があるのかが説明された上で、改善の方針と、改善結果の設計を示す」という流れで、具体的に、わかりやすく解説されています。
また、その設計に沿ったサンプルコードも、随所で示されています。
この他、アジャイル開発の本質とプラクティスや、デザインパターンの適用方法なども、非常に実践的に解説されています。
後半では、実際のシステムを開発するケーススタディに沿って、さらに具体的な実践例が示されます。
きちんと本質をおさえた上で、その実践まで具体的に示されている、素晴らしい本です。
Top
2013.03.11
リンク先が古くなっていた箇所を修正しました。
わかりやすくするために、説明の端々を改訂しました。
リンク先が古くなっていた箇所を修正しました。
わかりやすくするために、説明の端々を改訂しました。
0 件のコメント:
コメントを投稿