インターフェイス(interface)と抽象(abstract)クラス

詳しく分かりやすい説明をしてくれてるサイトが多いので、もはや、下記サイトをご覧になっていただければ済む話ですが、一応、自分なりにインターフェイス(interface)と抽象(abstract)クラスの違いを調べました。(ほぼ、他サイト様の流用です。) 

 

⇩  インターフェイスと抽象クラスについては下記サイトへ

[PHP] abstractとinterfaceの使い分けを整理してみる | Suinasia

PHPのオブジェクト指向入門 | オブジェクト指向PHP.NET

【 ほでなすPHP 】 PHP5の基本 - > インターフェイス

PHPのinterfaceとabstractを正しく理解して使い分けたいぞー ::ハブろぐ

 

まずは、それぞれの特徴を書き出します。

インターフェイス(interface)の特徴

 

メソッドの実装とは(Javaでの説明なので、PHPでも当てはまるか分かりません。)

メソッドの「本体」。
メソッド宣言直後にある{ }で囲まれた箇所を「メソッドの実装」と呼びます。
また、インターフェイスメソッドには実装がないため、インターフェイスからimplementsすることも「インターフェイスから実装する」と言いいます。

またそのクラスを「インターフェイス実装クラス」と言いいます。
そして、インターフェイスメソッドを「オーバーライド」することも「実装する」と言いいます。

インターフェイスメソッド宣言のみのため、そこに「実装を追加する」からです。

と言っても、一般的には「オーバーライドした」と言うことの方が多いです。
 
定義」とほぼ同意。

ですが、インターフェイスメソッドを「定義する」とはあまり言いいません。

一応「オーバーライド」のことを「再定義」と呼ぶことはあります。

 

⇩  上の説明は、PHPでの実装の説明が見当たらなかったので下記サイトのJavaでの実装の説明を抜粋させていただいてます

実装とは : JavaA2Z

implements

〈…に〉道具[手段]を与える。
《プログラムに機能を》 インプリメントする, 実装する。

 

抽象クラス(abstract)の特徴

  • キーワードabstractで定義します。
  • abstractとして定義されたクラスのインスタンスを生成することはできません。
    (継承された子クラスでインスタンス化が可能。)
  • 1つ以上の抽象メソッドを含む全てのクラスもまた抽象クラスとなります。
  • abstractとして定義されたメソッドは、そのメソッドの外観を宣言するのみで、 実装を定義することはできません。
  • abstract以外のメソッドは、実装を定義できます。
  • 抽象クラスから継承する際、親クラスの宣言で abstract としてマークされた 全てのメソッドは、子クラスで定義されなければなりません。
    メソッドは子クラスでオーバーライドされる必要がある。)
  • これらのメソッドは同等 (あるいはより緩い制約) の可視性(アクセス権) で定義される必要があります。
    (※例えば、抽象メソッドが protected として定義された場合、その関数の実装は protected または public のどちらかとして定義する必要があります。
    private にすることはできません。)
  • メソッドシグネチャも必ず一致していなくてはなりません。 すなわち、型ヒントや必須引数の数についても同じでなければならないということです。

キーワードのリスト

これらのキーワードは、PHP では特別な意味があります。
これらのいくつかは 関数やメソッドのようなものを表し、いくつかは定数のようなものを表す、 といったようになっていますが、実際にはそうではありません。
実際には、 これらは言語を構成するものです。
以下のキーワードはいずれも定数、クラス名、 関数名として使用することはできません。
これらを変数名として使用することは一般的には可能ですが、 混乱を生じる可能性があります。

PHP のキーワード
__halt_compiler() abstract and array() as
break callable(PHP 5.4 以降) case catch class
clone const continue declare default
die() do echo else elseif
empty() enddeclare endfor endforeach endif
endswitch endwhile eval() exit() extends
final finally(PHP 5.5 以降) for foreach function
global goto (PHP 5.3 以降) if implements include
include_once instanceof insteadof(PHP 5.4 以降) interface isset()
list() namespace(PHP 5.3 以降) new or print
private protected public require require_once
return static switch throw trait (PHP 5.4 以降)
try unset() use var while
xor yield (PHP 5.5 以降)
コンパイル時の定数
__CLASS__ __DIR__(PHP 5.3 以降) __FILE__ __FUNCTION__ __LINE__ __METHOD__
__NAMESPACE__(PHP 5.3 以降) __TRAIT__(PHP 5.4 以降)

 

継承の決まり事としてPHP: クラスの基礎 - Manual の説明によると

extends

クラスは、宣言部に extends キーワードを含めることで、他のクラスのメソッドと プロパティを継承することができます。
多重継承を行うことはできず、クラスが継承できるベース クラスは一つだけです。

継承されたメソッドやプロパティをオーバーライドするには、 親クラスで定義されているのと同じ名前でそれを再宣言します。
しかし、親クラスでそのメソッドfinal 定義されている場合はオーバーライドできません。

オーバーライドされた元のメソッドや静的プロパティにアクセスするには、 parent:: で参照します。

メソッドをオーバーライドするときには、パラメータのシグネチャも同じでなければなりません。
もし違っていれば、PHPE_STRICT レベルのエラーとなります。
ただしコンストラクタは例外で、 異なるパラメータでオーバーライドすることができます。

 

 

ISA(is-a)関係とCAN DO関係(Javaで言われてたことなのでPHPで成り立つのか分かりません)

クラスの継承(例抽象クラスと派生クラスの「継承」の関係)は ISA関係
A extends B
A は Bの一種と見なせる
----

インタフェースの実装(例:インターフェイスと実装クラスの「実装」の関係)は CAN DO関係
A implements B
A は Bのメソッドが実行できる

 

⇩  詳しくは下記PDF情報で。(内容がJavaっぽいんで、PHPにも当てはまるかは分かりません。) 

プログラミングⅡ 第12回 ---- オブジェクト指向型 プログラミング パラダイム

is-a

知識表現オブジェクト指向プログラミングオブジェクト指向設計では、is-aとは、あるクラスBはもう一つのクラスAのサブクラスである(また、AはBのスーパークラスである)という関係である。

言い換えれば、"BはAである"は通常、概念Bは概念Aの特化であり、概念Aは概念Bの汎化であることを意味する。

例として、「フルーツ」は「リンゴ」、「オレンジ」、「マンゴー」などの汎化である。

リンゴはフルーツである(is-a) (Apple is a fruit.)と言える。

オブジェクト指向プログラミングではis-a関係は継承という概念の中で使われる。

たとえばリンゴは、「果肉に種が入った植物」に属するというような、フルーツすべてに共通するプロパティをすべて継承するといって差し支えない。

is-a関係とは、異なる種類の階層の性質をもつ関係にhas-aがある。

オブジェクトと従属するオブジェクトの論理関係がis-aか、それともhas-aなのか、いつもはっきりと決定できるものではない。

この曖昧さが、is-aのようなメタ言語的な用語を生み出した。

 

インターフェイス(interface)、抽象(abstract)クラス共に単体では動けず

インターフェイスは、何かしらのクラスにimplementsされることで実装され、

抽象クラスは、自身以外のクラスに継承されないと動きださないようです。

他人がいないと成り立たない、まさに小判鮫みたいな感じでしょうか。

メソッドの内容(実装の定義)は派遣先で決められる

しかも、あろうことか、このインターフェイスと抽象クラスのお二方は、派遣先(実装・継承された先)のクラスにメソッドの内容を決めさせ(オーバーライドする)、更にこのメソッドを必ず実行するように強要するそうです。

なんか、嫌な感じなひとにしかみえないっす。 

インターフェイスはいくつでも実装できるし、継承もできる

 クラスが多重継承できないのに対し、インターフェイスはいくつでも盛り込めるようです。

しかも、インターフェイスは、クラスのようにインターフェイス同士の継承が可能。

 

インターフェイスはクラス使用者のために、抽象クラスはクラス設計者のために

抽象クラス

抽象クラスはあくまで複数のクラスの共通部分を抽出して一つのクラスとし、 処理の中身は違うけど(継承先の子クラスで定義されるまで抽象メソッドの実装は決まらない)必ず必要なメソッドは抽象メソッドとして定義し、 各クラスはこの抽象クラスを継承して独自の処理は勝手に作ってねってということらしいです。

クラス設計を楽にする、言ってみれば抽象メソッドはクラス設計者向けの仕組み。

 

インターフェイス

インターフェイスを実装しているクラスは、そのインターフェイスで定義されているメソッドが存在することを保証しています。(インターフェイス含まれる全てのメソッドはimplements先のクラスで実装される必要があるため。

インターフェイスメソッドは、implements先のクラスで実装が定義されるので、普通だったらクラスで定義されてるメソッドの実装を確認したい時に、クラスを探して確認しなければいけませんが、その必要がなくなります。

インターフェイスはクラス使用者向けの仕組み。

結論

インターフェイスも抽象クラスも、最初は嫌なひとという印象でしたが、クラス設計者・使用者を助けてくれる立派なしくみだったんですね。

使いこなせるように勉強していかねばです。