委譲について学ぶ

はいどーもこんばんは、もうすぐでプログラマのツミオです。
本日は委譲について学びたいと思います(デリゲートではないです)。

言語はC#ときどきJavaScriptです。

委譲ってなんやねん

「委譲」という言葉は、一般的な日本人にとって馴染みがありませんよね。
というわけで辞書を使いましょう。
広辞苑第六版にはこう書いています。
「他にゆだねゆずること」

プログラミングでも同じです。
「他にゆだねゆずること」をプログラミングの中でおこなうのです。

具体的なサンプル

さっそく具体的なサンプル(コンソールアプリケーション)を見ていきましょう。

AnimalクラスとPeopleクラスがありますね。
Animalクラスはコンストラクタの引数に名前を取ります。
そしてHuntメソッドを実行すると、「俺がモンスターハンターだby自身の名前」とコンソール画面に表示します。
特に難しいことはないですね。

お次はPeopleを見てみましょう。
PeopleクラスはAnimalクラスのインスタンスをコンストラクタ引数に取ります。
そしてAnimalクラスと同様、Huntメソッドを持っています。
このHuntメソッドの処理は、コンストラクタ引数で受け取ったAnimal型のインスタンスのHuntメソッドに処理を完全に任せています。
つまり委譲しています(Peopleクラス自体での独自の処理は何もない)。

ちなみにMainメソッド内はこんな感じで書きます。

もう少しオブジェクト指向っぽく書く

さて先ほどのコードをもう少しオブジェクト指向っぽく書いてみましょう。
というわけでコードをドン。

まずIHuntingインターフェイスが宣言されていることがわかると思います。
このインターフェイスを使用したい場合、Huntメソッドの実装が強制されます。

Animalクラスは先ほどのIHuntingインターフェイスを実装しています。
が、実際の中身はあんまり変わりません。
アクセス修飾子なんかが変わったくらいでしょう。

新しくBirdクラスが宣言されています。
このBirdクラスはAnimalクラスを継承しているため、すなわちIHuntingインターフェイスがもつHuntメソッドの実装が強制されます。
今回はオーバーライドし、別の文字をコンソールに表示するよう変えました(必ずしもオーバライドする必要はない)。

最後にPeopleクラスですね。
Peopleクラスのコンストラクタは二種類あります(コンストラクタのオーバーロード)。
すなわち何も引数に取らないバージョンと、IHunting型を引数に受け取るものです。

ここで注目していただきたいのが、先ほどのAnimalプロパティがAttackerプロパティへと変わったことです。
これはIHunting型となっています。
つまり、IHuntingインターフェイスを実装している型ならば、People型だろうがAnimal型だろうがBird型だろうが引数に受け取れるのです!

で、肝心のHuntメソッドの内容ですが、Attackerがnullなら人間自身がハンティングを開始します。
アタッカーがいる場合は、そのアタッカーにハンティングを委譲します。
なお、?.となっているのはnull条件演算子です。

Mainメソッドにはこんな感じで書いてみてください。

最初のpeopleはいいですね。
次のpeople2ではインスタンス生成時、さらに別のPeople型のインスタンス(奴隷)を生成しています。
people2.Hunt()と実行すると、この生成された奴隷が泣く泣くハンティングを開始するのです。

その次のpeople3は人間のインスタンスを生成し、その中でさらに別の人間を生成し、その生成された人間が今度はAnimal型のインスタンスを生成しています。
王が調教師に「ハンティングしてこい」と命令(委譲)し、その調教師が百獣の王に「ハンティングしてこい」と命令(委譲)し、結局のところ百獣の王がハンティングを開始したと考えるとわかりやすいのではないでしょうか?

次の宣言ではIHunting型の変数birdがBird型のインスタンスを生成していますね。
ヤタガラス君は己自身を鳥族最強のモンスターハンターだと思っています。

その後、さらにIHunting型の変数people4は、先ほど生成したヤタガラス君を引数として受け取り、要は彼を使役しています。
己自身を最強の鳥属だと思っていても、結局は人間に使われるヤタガラス君なのでした。
あな悲し。

おわりに

いかがでしたでしょーか。
僕自身も勉強中の身ですが、少しでも参考になれば幸いです。

最後にJavaScriptで書いたバージョンも置いておきます。

注*ただしJavaScriptにはインターフェイスという概念がありません。継承の仕方をよく考える必要があるかなと思いました。
また、JavaScriptは言語仕様としてコンストラクタのオーバーロード(多重定義)を認めていません。こちらも少し特殊な書き方をする必要があるかなと思います。

フォローする