連載C#入門第15回 インターフェイスの活用 |
インターフェイスの効能
インターフェイスの機能はすでに第4回で紹介済みなので、いまさらという印象を受けるかもしれない。しかし、まだまだインターフェイスについて語っていない内容も多い。
初心者の場合、自分でインターフェイスを定義する機会は多くないかもしれない。しかし、システム側で定義しているいくつかのインターフェイスを自作クラスに実装すると、いろいろと便利な機能が有効になる。この方法は初心者でも知っておく価値があるだろう。
今回は、インターフェイスの機能概要を説明した後で、システムが定義するインターフェイスを活用すると何ができるのかを紹介しよう。
さて、まずは、インターフェイスの最も基本的な効能から説明しよう。
以下のサンプルソースでは、継承関係がまったくないクラスであるClass2とClass3を定義している。しかし、この2つのクラスには、同じtaskという名前のメソッドがある。ある外部のメソッドから、Class2とClass3の違いに関係なく、taskメソッドを呼び出したいとしよう。これをインターフェイスを用いて解決した例が以下である。
|
|
インターフェイスの最も基本的な効能を示すサンプル・プログラム1 | |
異なるクラスにある同じ名前のメソッドを、クラスの違いとは無関係に呼び出す。 |
これを実行すると以下のようになる。
サンプル・プログラム1の実行結果 |
インターフェイスへの参照を利用して、メソッドが呼び出される。 |
ここでポイントになるのは、25〜28行目のメソッドcallTaskである。このメソッドの中から、Class2とClass3に含まれるtask()を呼び出したいのである。だが、通常は継承関係もないクラス間で、共通のメソッドを持つことはできない。なお、厳密にいえば、すべてのクラスは、System.Objectから派生しているものなので、継承関係がないといえば嘘になるのだが、System.Objectは勝手に書き換えられないクラスなので、この手の問題解決には役に立たないため範囲外と考え、無関係と記述することにする。
それはさておき、無関係なクラス間で共通のメソッドを持つには、インターフェイスを共有する、という方法がある。上記のソースは、それを実践した例である。見て分かるとおり、Class2とClass3は、共通のインターフェイスISpecialTaskを実装している。5〜8行目で、ISpecialTaskはtask()というメソッドを実装すべきことを示している。ここではメソッドの内容は記述されない。あくまで、引数と戻り値だけが指定される。この例ではどちらもないことが明示されている。そして、9行目と16行目は、それぞれのクラスが、このインターフェイスを実装することを明示的に指定している。実装内容は、11〜14行目と、18〜21行目にある。そして、25〜28行目のcallTaskメソッドは、引数としてISpecialTaskインターフェイスへの参照を取るように記述されている。ISpecialTaskを実装したクラスのインスタンスからは、必ずこのインターフェイスへの参照を取得できる。つまり、Class2のインスタンスからも、Class3のインスタンスからも取得できることになる。そのため、33〜34行目のように、どちらのクラスのインスタンスも、引数に渡すことができる(厳密にいえば、インスタンスへの参照から、インターフェイスへの参照が取り出されて、それがメソッドに渡る)。
継承で実現した例
上の例は、インターフェイスを使わなくても、継承を使って実現できる。実際に継承を使った例を以下に示す。
|
|
インターフェイスではなく継承を使用したサンプル・プログラム2 | |
プログラムの構成はインターフェイスを使用した場合とほぼ同じになっている。 |
これを実行すると以下のようになる。
サンプル・プログラム2の実行結果 |
実行結果も当然インターフェイスを使用した場合と同じになる。 |
すでに継承は説明済みなので、ソースコードの解説は割愛する。ここで理解していただきたいことは、インターフェイスを1つだけ実装する場合は、継承を用いても、ほぼ同等の機能を実現できるということである。しかし、実装するインターフェイスが2つになると、継承で類似機能を記述することはできなくなる。以下は、クラスが2個のインターフェイスを実装している例である。
|
|
2つのインターフェイスを実装したサンプル・プログラム3 | |
継承では類似の機能を記述することはできない。 |
これを実行すると以下のようになる。
サンプル・プログラム3の実行結果 |
2つのクラスにある2つのメソッドが、それぞれ順に呼び出される。 |
インターフェイスも継承も、ソースコード上では同じように見える。クラス宣言のクラス名の後に、コロン記号(:)を書いて、その後にインターフェイスか継承するクラス名を記述する。だが、両者の間で決定的に違うのは、インターフェイスの名前は何個でも記述できるのに対して、継承するクラス名は1個しか記述できないことである。
このような制限は、技術的なものではない。事実C++では、継承するクラス名をいくつ書いてもよい。これを多重継承という。多重継承ができれば、インターフェイスはなくてもよい。事実、C++にインターフェイスはない。にもかかわらず、C#やJavaといった比較的新しい言語で多重継承が禁止されているのは、継承が過剰に強力すぎる機能であり、トラブルを引き起こしやすいという経験による。強力すぎる継承の機能を、適正な水準まで制限した結果が、継承するクラスは1個までという制約と、インターフェイスの導入である。そのようなわけで、C#では、継承とインターフェイスを適切に使い分けねばプログラムが組めない。どういうときに、どちらを使うのかは、.NET Frameworkのリファレンスなど、実例を見ているうちに、何となく分かってくると思う。おおざっぱにいえば、機能性を継承するときは継承を使い、呼び出し方法を合わせるときはインターフェイスを使うのである。
INDEX | ||
第15回 インターフェイスの活用 | ||
1.インターフェイスの効能 | ||
2.インターフェイスの継承 | ||
3.同名のメソッドを持つインターフェイス | ||
4.ソート順を操る | ||
「C#入門」 |
- 第2回 簡潔なコーディングのために (2017/7/26)
ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている - 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう - 第1回 明瞭なコーディングのために (2017/7/19)
C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える - Presentation Translator (2017/7/18)
Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
|
|