機能の拡張 -インターフェイス-

ホームC#プログラミング応用講義 > インターフェイス

目次

オブジェクト指向三要素

このインターフェイスはオブジェクト指向の三要素の1つ「多様性」を実現する機能です。そういえば、まだオブジェクト指向の三要素を詳しく記述していませんでした。

まず三要素というからには3つあります。「カプセル化」「継承」「多様性」がその3つです。これらはそれぞれ覚えておくべき知識です。オブジェクト指向三要素は重要ですから。

「カプセル化」とは要するに「オブジェクト」が存在することです。オブジェクトの中にメソッドなどのメンバをすべて放り込み、完全に独立した働きをするものとなります。
これがカプセル化の概要ですが、クラスはカプセル化を実現する手段ということになりますね。オブジェクトを生成する設計図ですから、クラス自体はオブジェクトではありません。

「継承」は応用講義でも詳しく扱いました。継承がなければ完全に独立した働きをするオブジェクトを、何の関連性もなく莫大な量定義することが必要となります。
継承があることによって「派生クラスは必要な分だけ」実装することができるのであり、なければ大変なことになります。

そして最後が「多様性」。これはしばしば「ポリモーフィズム」と呼ばれますが、なにか「レンズの屈折」のような感じがするので私は多様性と呼ぶことにします。
それはさておき、多様性とは「応用性がある」という意味でとればいいでしょう。「つぶしがきく」になるとニュアンスが代わりますが、要するに「いろいろ使えちゃう」ということです。

いろいろ使えるためには、その使うものが「具体的」であってはいけません。「抽象的」であって初めていろいろな場面で使うことができるのです。
例えば「トリック」というと、一部の熱烈的ファンしか話が合いませんが、「ドラマ」というとそのバリエーションは広がります。その分内容は浅くなりますが。

内容が浅くなるのは当然です。抽象的なのですから。抽象的という言葉を連発しているのは「抽象クラス」「抽象メソッド」を思い出していただくためです。
これらはいかにも抽象的でした。しかし C# には、さらに抽象化を進めた機能があります。先ほどの例で言えば「ドラマ」をさらに「文学」に広げた感じでしょうか。
え?ドラマは文学ではない? 「娯楽」にすべきだ? いえいえ、私は本気で「ドラマは文学だ」と思っています。

話し戻って究極的に抽象的なのがここで紹介する「インターフェイス」というものです。
インターフェイスは抽象そのものであるため、中身が一切ありません。すなわち何も実装しないということです。
「有名無実」という言葉がありますが、まさに名前はあるのに中身はないのがインターフェイスなのです。

制限

まずインターフェイスもクラスと同じように定義しますが、もちろんキーワードは class ではありません。
カタカナを英語に直した(元は逆か...)「interface」です。これをインターフェイス名の前につけます。

そして、インターフェイスは中身がありませんから、どこかで実装されなければ意味がありません。
その実装は当然クラスで行います。

あるインターフェイスを使って、あるクラスを定義するのは派生となんら変わりはありません。「:」コロンを使って指定します。
いくつも指定したい場合は「,」コンマで区切って書き並べ、基本クラスとインターフェイスを同時にクラスに継承させたい場合は基本クラスを先に書きます。

基本構文はこれまでですが、いくつか留意点があります。
その1つは大変重要で、「インターフェイスに実装するメンバはすべて public のみ」です。

すなわち、すべて public なら、.NET の作者さんがすべて public になるように設計しているので public はつけないということになります。
アクセス修飾子不要というのは重要です。

そして「再定義の際はシグニチャが完全一致」も重要です。
こちらはいろいろなところでシグニチャの一致を経験していますから慣れていると思いますが、忘れがちなのが「public」の付け忘れです。

インターフェイスはすべて public だから public は要りませんが、インターフェイスを実装していくクラスはすべて public とは限りません。
そのため private/public の指定をしますが、この指定を省くと private になります。そのため、シグニチャの完全一致に適しません。
インターフェイスの内容を定義する際は必ず「public」をつけることをお忘れなく。

そしてあと1つ。「インターフェイスの全実装」があります。
インターフェイスに記述したすべてのメンバは、派生クラスの中ですべて定義しなければなりません。この辺りがインターフェイス独自で、選択的実装は許可されません。
こいつは実装してやるけど、こいつは要らないからいいや、というわけにはいかず、すべて実装する必要があります。

制限はこれだけで、基本クラス・派生クラスの関係同様、「派生クラスはインターフェイスをがっぽり飲み込む」と考えていいですから、派生クラスでのインターフェイス定義は楽です。

使ってみる

ではサンプルを見てみましょう。今回はサンプルの登場が遅くなりました。前置き長すぎたかな?
using System;

interface TRICK
{
    void TRICK1(string str);
    void TRICK2(string str);
}

class Exam1 : TRICK
{
    public void TRICK1(string str)
    {
        Console.WriteLine("TRICK1は" + str + "です。");
    }
    
    public void TRICK2(string str)
    {
        Console.WriteLine("TRICK2は" + str + "です。");
    }
}

class Exam2 : TRICK
{
    public void TRICK1(string str)
    {
        Console.WriteLine(str + " -- TRICK1");
    }
    
    public void TRICK2(string str)
    {
        Console.WriteLine(str + " -- TRICK2");
    }
}

class Demo
{
    public static void Main(string[] args)
    {
        Exam1 ex1 = new Exam1();
        ex1.TRICK1("深夜番組の出世頭");
        ex1.TRICK2("ゴールデン並みの視聴率を記録したドラマ");
        
        Exam2 ex2 = new Exam2();
        ex2.TRICK1("仲間由紀恵初主演ドラマ");
        ex2.TRICK2("ゴールデン初主演『ごくせん』のオファーを呼んだドラマ");
    }
}
サンプル自体よりも表示する文字列、特に Exam2 の方を決めるのに時間がかかったサンプルです。
それはさておき、早速見ていきます。

まず、interface が見つかります。インターフェイス名は TRICK です。
中には TRICK1() と TRICK2() が、中身抜きすなわち実装なしで記述されています。この場合定義とはいえません。なんと言っていいのかわからないので記述ということにしておきます。

この記述部分には public が付いていないことを確認してください。
それ以外は特に変わったところもありません。string 型を1個引数にとるんだなくらいは確認しておきます。

Exam1 と Exam2 は並列的なクラスで、表示形式が違うという点が唯一の違いです。
基本クラス同様インターフェイスを飲み込んでいますので、一見すると TRICK は基本クラスか、と思うかもしれません。形式は同じですから無理もありません。

その両クラスの中の、インターフェイスのメソッドを実装する際には public が付いていることに注意してください。
面倒くさくてインターフェイスをコピペしてたりすると間違えます。私がよくするうっかりミスというやつでしょう。

あとは Demo クラスですが、こちらも変わった点はありません。普通にオブジェクトを生成し、メソッドにアクセスしているだけです。

で、始めに述べた「多様性」がどこにあるのか、という話になりますが、これは私があえて Exam1 と Exam2 を作った点にあります。
このプログラムの中でメソッドというと3つです。TRICK1() ・ TRICK2()、そして Main() です。

ところが、実際にはそれぞれ2つの実装内容を持っています(Main() は除く)。Exam1 と Exam2 では実装が異なりますから、単に TRICK1() といっても2種類あるかのように見えるわけです。

しかし、これだけなら何もインターフェイスを使わなくてもできます。ところが、インターフェイスを使うことによってある秩序が生まれます。
1つのインターフェイスから複数のメソッドを定義するのだ、という一体感というのでしょうか。

Exam1 Exam2 それぞれでメソッドを定義するのではなく、メソッドの名前をインターフェイスに記述し、内容をそれぞれのクラスで実装することで、インターフェイス自体が多様な形態を持っているということになります。
これがインターフェイスにおける多様性です。

多様性と呼ばれるものはインターフェイスだけではありません。抽象メソッドなどもそうですし、メソッドのオーバーロードという機能も多様性に属しているといえます。
インターフェイスはそのような多様性の機能の中で最も抽象的な概念です。

[ ステップアップC# ] [ C#プログラミング応用講義 ]