委譲の隠蔽について学んでみる

はいどーも世間から隠蔽されてる無職です。
本日は「委譲の隠蔽」について学んでみようと思います。

委譲の隠蔽ってなんやねん

「クライアントクラスがあるオブジェクトの委譲クラスを呼び出している場合、サーバにメソッドを作って委譲を隠す」ことを委譲の隠蔽と言うそうです(リファクタリング技法の一つです)。
ぶっちゃけ「ナンノコッチャ」感が強いですが、コードを見たら意図はすぐにわかりました。
というわけで、まずは委譲の隠蔽をしていないコードをドン。

先ほどの「クライアントクラスがあるオブジェクトの委譲クラスを呼び出している場合、サーバにメソッドを作って委譲を隠す」に沿って用語を当てはめてみると、以下のようになります。

クライアントクラス:Programクラス
あるオブジェクト:Playerクラス
委譲クラス:CharacterInformationクラス
サーバ:Playerクラス

ここで問題となっているのは、委譲クラス(CharacterInformation)が変更されたとき、クライアントクラス(Programクラス)が影響を受けてしまうことです。
また、クライアントクラスはPlayerクラスの使い方だけではなく、CharacterInformationクラスの使い方も知っていなければならないことになります。
この問題を解決するために使うのが「委譲の隠蔽」というリファクタリングです。

委譲の隠蔽をしてみる

ここでは『新装版 リファクタリング』の手順に従って委譲の隠蔽をおこなっていきたいと思います。
というわけで、まずは委譲クラスのメソッド(Print)に対応する単純な委譲メソッドをサーバに作成します。
こんな感じですね。

次にクライアントがサーバを呼び出すように調整します。
こんな感じですね。

ここでコンパイルし、テストします(説明簡略化のためテストは実装していませんが、要はコンソール画面に以前と変わらず「情報を表示ペラペラペラペラ」と表示されたらOK」。

最後にサーバの委譲クラスへのアクセサを取り除きます。

さらにここでもう一度コンパイル・テストをおこないます。
うまく動けばOKです。

委譲の隠蔽をしないとどうなるか

以上でリファクタリングは完了です。
では委譲の隠蔽をしている場合と、していない場合でどんな差があるのか見てみましょう。
具体的には最初に書いた
「委譲クラス(CharacterInformation)が変更されたとき、クライアントクラス(Programクラス)が影響を受けてしまうことです。」
「また、クライアントクラスはPlayerクラスの使い方だけではなく、CharacterInformationクラスの使い方も知っていなければならないことになります。」
この二つですね。
後者についてはそのままなので、前者について詳しく見ていきます。

まずCharacterInformationクラスのPrintメソッドの処理およびシグネチャが変更されたとします。
例えばこんな感じ。

このとき、クライアントクラスには影響を与えたくないとします。
もしもリファクタリングしていれば話は簡単です。
PlayerクラスのPrintクラスを変更すればいいのです。
同じように出力するならこんな感じ。

クライアントクラスが利用しているのはあくまでもPlayerクラスのPrintメソッドであり、Printメソッドのインターフェイスは何も変更されていません。
したがって、クライアントクラスが変更することも何もありません。
CharacterInformationを直接利用しているPlayerクラスだけが変更の影響を受けます。

もしこれがリファクタリング前の場合だと、どうなるでしょうか。
クライアントクラスにまで変更が波及することが容易に想像できるかと思います。

何が嬉しいのか

ただ今回の例だと「それくらい困らんのじゃ?」と思うかもしれません。
ですが例えばPlayerクラスが複数のクライアントクラスから利用されていることを考えてみてください。
そして、リファクタリング前の状態でPrintクラスを「player.Info.Print();」のように使っていたとして考えてみてください。
今回のような小さな変更でさえ、全てのクライアントクラスに対して「player.Info.Print();」と書いていた箇所を全て「player.Info.Print(message:"情報を表示ペラペラペラペラ", count:1);」と修正していかなければなりません(あるいはもっと複雑なメソッドなら、さらに面倒なことになります)。
一方でPlayerクラスの中に委譲が隠蔽されていたなら、クライアントクラスに対する修正はゼロです。
プログラマはただPlayerクラスだけを見ればよいことになります。修正箇所も一箇所です。これはプログラマにとっては喜ばしいことですね。

逆のリファクタリングもある

これまで見てきたように、委譲の隠蔽をおこなうにはサーバに委譲メソッドを追加しなければなりません。
数が多くなると苦痛ですし、場合によっては委譲オブジェクトを直接呼ばせたほうが便利だということもあるでしょう。
『新装版 リファクタリング』には委譲の隠蔽とはちょうど真逆のリファクタリングも紹介されています。
それが仲介人の除去です。
やっていることは本当に委譲の隠蔽の真逆なだけなので説明は省略しますが、「あちらを立てればこちらが立たず」な感じがして面白いなと思いました。

終わりに

委譲の隠蔽を通じて、リファクタリングと言っても「これをしておけば必ず正解」というものはないのだなあと勉強になりました。
時と場合によって「正解はコチラ」となるのですね。
言い換えれば、「今正解かもしれないリファクタリングは将来また別のリファクタリングをする必要が出てくるかもしれない」ということです。
もっというと「元に戻す必要が出てくる」かもしれない、ということですね。
でも気軽に変更できることこそがリファクタリングをし続ける強みなので、あんまり気にすることはなさそうです。
僕もガンガンリファクタリングしていきたいですね。

まだ『新装版 リファクタリング』は半分も読めていないですが、この調子で勉強を続けようと思いますよ。
ほなそんな感じでまた。

フォローする