[オブジェクト指向]interfaceについて考えてみた

todaclass, interface, PHP, オブジェクト指向

今までオブジェクト指向でプログラムを書いて、はや○年たちますが、
つい最近まで、abstractなclassと、interfaceの使い分けが理解できていませんでした。
(もちろん、言語仕様としてのinterfaceの知識は持ってますが)

abstractなclassを使用した場合でも、その子classが備えているべきinterfaceを規定することが可能だからです。なぜinterfaceという仕組みを言語に組み入れる必要があるのか疑問を持ってしまいました。

この点について、先日ようやく理解ができたのでまとめてみます。

PHP5にはCountableというinterfaceが定義されています。

interface Countable {
/* メソッド */
abstract public int count ( void )
}

http://jp.php.net/manual/ja/class.countable.php

このinterfaceを実装(implement)すると、そのinstanceを標準のcount()関数の引数に渡したときに、count()メソッドを呼び出してくれます。

説明
abstract public int Countable::count ( void )
このメソッドは、Countable を実装したオブジェクトで count() 関数を使用した際に実行されます。

たとえば、ツリー構造を表すTreeというclassを例にとると下のようになるでしょう。

class Tree implement Countable
{
   public function addNode(Tree)
   {
      ノードを追加;
   }

   public function count()      <-- Countable::count()の実装
   {
      return ノードの数;
   }
}


$tree = new Tree();
$tree->addNode(..);
$tree->addNode(..);
$tree->addNode(..);

echo count($tree);     // $tree->count()  --> 3

count()関数は、渡されたinstanceのclassがCountableというinterfaceをimplementしていることを確認すれば、安全にcount()メソッドを呼び出すことが可能になります。

自前でcount()関数を書いてみるとこんな感じになるでしょうか:

function count($obj)
{
    if($obj instanceof Countable){
          // $objはCountableをimplementしているので、count()を呼び出しても安全
          return $obj->count();
    } else if(){
        ...以下略
}

このようにinterfaceとはclassの備えているべき仕様(性質)を定義するべきものであると理解できます。
そしてclassはそのinterfaceをimplementすることで仕様を実装するわけです。

また、このようなCountableという性質の実装をclassの継承としてやろうとすると、関係の無いclassが同じ親classを持つことになり、(内包関係としての)is-a関係が保てなくなってしまいます。

C++のような多重継承をサポートする言語では、interfaceのimplementをclassの継承として定義したため、いわゆるダイヤモンド継承(詳しくはwikipedia参照)という問題を抱え、仕様の複雑化、コードの複雑化を招きました。

対してJavaやPHPのような単一継承のみをサポートする言語においては、classの内包関係としての継承と、仕様の実装(implement)を区別したものであると考えられます。

todaclass, interface, PHP, オブジェクト指向

Posted by toda