インターフェイスまたは抽象クラス:どちらを使用するか?


回答:


458

システム(自分自身を含む)で作業する開発者に、作成するクラスに一連のメソッドを実装するように強制する場合は、インターフェースを使用します。

お使いのシステムで作業する開発者を強制したいとき、抽象クラスを使用してメソッドのセット番号を実装するために(自分を含む)、あなたは彼らの子クラスを開発するのに役立ちますいくつかの基本メソッドを提供したいです。

留意すべきもう1つの点は、クライアントクラスは1つの抽象クラスしか拡張できないのに対し、クライアントクラスは複数のインターフェースを実装できることです。したがって、抽象クラスで動作コントラクトを定義している場合、つまり、各子クラスは単一のコントラクトにのみ準拠することができます。ユーザープログラマーを特定のパスに沿って強制したい場合、これは良いことです。時にはそれは悪いでしょう。PHPのCountableおよびIteratorインターフェースがインターフェースではなく抽象クラスであると想像してください。

どちらに進むかが不明な場合によくあるアプローチの1つは(以下のcletusで説明されているように)、インターフェイスを作成し、抽象クラスにそのインターフェイスを実装させることです。


12
abstractinterfaceクラスの使用法を理解するために一日中試みていました、あなたの投稿はそれをすべて明らかにしました。
どうも

4
抽象クラスのもう1つの利点は、抽象保護メソッドを定義できることです。常に役立つわけではありませんが、一部のアーキテクチャでは便利です。
ネットコーダー、2011年

したがって、多くの場合、柔軟性のために抽象クラスを使用する必要があります-それが私の結論です:)
ymakux

3
@volocuga:必ずしもそうではありません。アランが指摘したように、拡張できるのは1つの要約だけです。IMOはコードの難読化に寄与し、直接性が低いため、私は抽象的にインターフェイスのアイデアを実装するのが好きではありません。
2014年

171

an Abstract Classとan の違いInterface

抽象クラス

抽象クラスはいくつかの機能提供し、残りを派生クラスに任せることができます

  • 派生クラス、基本クラスで定義された具象関数をオーバーライドする場合とオーバーライドない場合があります

  • 抽象クラスから拡張された子クラスは、論理的に関連付けられている必要があります。

インターフェース

インターフェイスに機能を含めることはできません。それは唯一の方法の定義が含まれています。

  • 派生クラスは、インターフェイスで定義されたすべてのメソッドのコードを提供する必要があります

  • 完全に異なる関連のないクラスは、インターフェースを使用して論理的にグループ化できます。


1
それを実証するための実際の例を提供できますか?
RNクシュワハ2015

1
abstract class X implements Yとは class X implements Yどう違いますか?
Webinan、2015

3
@Webinanではabstract class X implements Y、Xのバルク機能を派生クラスに実装し、抽象クラスと派生クラスの両方にYで定義された関数を含める必要があることを宣言しますclass X implements Yが、クラスXにはYで定義された関数を含める必要があることだけを意味します。は、XIが実際にインターフェースとしてのYの定義をスキップし、Yの関数をpublic / protected / private抽象関数として実装するだけで、派生クラスに実装されていることを確認する以外のクラスによって実装されることを意図していません。
CalleBergström2016

1
インターフェイスには、メソッドの定義だけでなく定数
Thielicious

あなたの比較が好きだった。だから何かを追加したかった。インターフェイスは、クラス定数をそのまま使用できますが、抽象クラスは使用できません。
ノーマンイブラヒム

128

なぜ抽象クラスを使用するのですか?以下は簡単な例です。次のコードがあるとします。

<?php 

class Fruit {
    private $color;

    public function eat() {
        // chew
    }

    public function setColor($c) {
        $this->color = $c;
    }
}

class Apple extends Fruit {
    public function eat() {
        // chew until core
    }
}

class Orange extends Fruit {
    public function eat() {
        // peeling
        // chew
    }
}

今、私はあなたにリンゴを与え、あなたはそれを食べます。どんな味?りんごの味です。

<?php 
$apple = new Apple();
$apple->eat();

// Now I give you a fruit.
$fruit = new Fruit();
$fruit->eat();

それはどんな味ですか?まあ、それはあまり意味がありませんので、あなたはそれをすることができないはずです。これは、Fruitクラスを抽象化し、その内部にeatメソッドを作成することで実現されます。

<?php 
abstract class Fruit {
    private $color;

    abstract public function eat(){}

    public function setColor($c) {
        $this->color = $c;
    }
}
?>

抽象クラスはインターフェイスに似ていますが、メソッドは抽象クラスで定義できますが、インターフェイスではすべて抽象です。抽象クラスには、空のメソッドと作業/コンクリートメソッドの両方を含めることができます。インターフェースでは、そこで定義された関数に本体を含めることはできません。抽象クラスでは可能です。

実際の例:

<?php 
abstract class person {

    public $LastName;
    public $FirstName;
    public $BirthDate;

    abstract protected function write_info();
}

final class employee extends person{

    public $EmployeeNumber;
    public $DateHired;

    public function write_info(){
        //sql codes here
        echo "Writing ". $this->LastName . "'s info to emloyee dbase table <br>";   
    }
}

final class student extends person{

    public $StudentNumber;
    public $CourseName;

    public function write_info(){
        //sql codes here
        echo "Writing ". $this->LastName . "'s info to student dbase table <br>";
    }
}

///----------
$personA = new employee;
$personB = new student;

$personA->FirstName="Joe";
$personA->LastName="Sbody";

$personB->FirstName="Ben";
$personB->LastName="Dover";

$personA->write_info();
// Writing Sbody's info to emloyee dbase table
$personB->write_info();
// Writing Dover's info to student dbase table 

2
こんにちは、この回答は、フォーマットの方法が原因でおそらく反対票を獲得しました。それが大きなコードブロックではない場合(4つのスペースがコードブロックに何かを挿入し、テキストのインデントを解除して、ブロックから取り出す)、これがどこかからコピーアンドペーストされた場合(そのように見えます)それらを信用するのは礼儀でしょう。
Camilo Martin

9
実例の男を愛してます!私がphpを学習し始めてから、この例では、感謝の気持ちがはっきりと表れます
Raheel

23
+1 What does that taste like? Well, it doesn't make much sense, so you shouldn't be able to do that.私は抽象を知っています!
Webinan、2015

finalキーワードは何をしますか?投稿ありがとうございます。
Gus

1
@VineeshKalarickal Personの例で理解できないのは、次の違いです。1)(例のように)抽象クラスPersonを使用する。2)Personを標準クラスとして記述し、EmployeeとStudentにwrite_info()メソッドをオーバーライドさせます。
Ferex、

66

ベストプラクティスは、インターフェイスを使用して、コントラクトと抽象クラスをその1つの実装として指定することです。その抽象クラスは多くのボイラープレートを埋めることができるため、特定の実装を使用せずに、必要なものまたは必要なものをオーバーライドするだけで実装を作成できます。


37

これをミックスに投入するだけですが、Cletusが抽象クラスと組み合わせてインターフェースを使用することを述べたように、私はしばしばインターフェースを使用して、私のデザイン思考を明確にします。

例えば:

<?php
class parser implements parserDecoratorPattern {
    //...
}

このようにして、私のコードを読んでいる人(およびデコレータパターンが何であるかを知っている人)は、a)パーサーの構築方法とb)デコレータパターンの実装に使用されているメソッドを確認できます。

また、ここではJava / C ++ / etcプログラマーではないので、データタイプが関係する場合があります。あなたのオブジェクトはタイプであり、あなたがそれらをタイプの周りに渡すとき、プログラム的に重要です。収縮可能な項目をインターフェイスに移動すると、メソッドが返す型が決まるだけで、それを実装するクラスの基本型は決まりません。

遅いですし、より良い擬似コードの例を考えることはできませんが、ここに行きます:

<?php
interface TelevisionControls {};
class Remote implements TelevisionControls {};
class Spouse implements TelevisionControls {};
Spouse spouse = new Spouse();
Remote remote = new Remote();
isSameType = (bool)(remote == spouse)

1
なんて素晴らしい例でしょう!;)
ジョエルマーフィー

@ matt2000性差別的ではなく、同性結婚にも対応しています。素晴らしい編集。:)
Austen Hoogen 14

4
これは素晴らしい例です!ただし、抽象クラスをインスタンス化することはできないと思います。抽象クラスから拡張したクラスです
Arielle Nguyen

2
sudoコードを少なくとも問題の言語のように見せるために殺すことはありません。誰かがそこにいくつかの$を入れるべきです。
クマを1回レスリングしました。

2
この例は面白いですが、抽象クラスを直接インスタンス化することはできません。例で変更を加えて、PHPで有効な使用法であると人々が考えないようにしてください。
saji89

16

主な違いは、抽象クラスにはデフォルト実装を含めることができるのに対し、インターフェースには含めることができないことです。

インターフェイスは、実装のない動作のコントラクトです。


16

また、ここで付け加えておきたいのは、他のオブジェクト指向言語にはなんらかの種類のインターフェースがあり、抽象化も、PHPと同じ意味と目的があるということではありません。抽象化/インターフェースの使い方は少し異なりますが、PHPのインターフェースには実際には実際の機能はありません。それらは単に意味論的およびスキーム関連の理由で使用されます。重要なのは、将来の開発者がまったく異なる使用計画を持っているかどうかに関係なく、プロジェクトをできるだけ柔軟で拡張可能で、将来の拡張に対して安全にすることです。

英語が母国語でない場合は、抽象化とインターフェースが実際に何であるかを検索する可能性があります。そして、同義語も探してください。

そして、これは比喩としてあなたを助けるかもしれません:

インターフェース

たとえば、イチゴで新しい種類のケーキを焼いて、材料と手順を説明するレシピを作成したとします。なぜそれがそんなに美味しいのか、そしてあなたのゲストがそれを好むのはあなただけです。次に、他の人もそのケーキを試すことができるように、レシピを公開することにしました。

ここでのポイントは

-それを正しくするために
-注意
すること-(イチゴが多すぎるなど)悪化する可能性があることを防ぐため
-それを試してみる人が簡単にできるようにすること
-何をすべきか(攪拌のような時間)を伝えること)
-実行できるが、実行してはいけないことを伝える

まさにこれがインターフェースを説明するものです。これはガイドであり、レシピの内容を観察するための一連の指示です。PHPでプロジェクトを作成し、GitHubまたは仲間などでコードを提供する場合と同じです。インターフェースは、人々ができることとすべきでないことです。それを保持するルール-あなたがそれに従わない場合、全体の構造が壊れます。


抽象化

ここでこの比喩を続けます...想像してみてください、あなたは今回、そのケーキを食べるゲストです。次に、レシピを使用してそのケーキを試します。ただし、新しい材料を追加したり、レシピに記載されている手順を変更またはスキップしたりする必要があります。それでは次に何が来るのでしょうか?そのケーキの別のバージョンを計画します。今回はイチゴではなくブラックベリーとバニラクリームを加えた...おいしい。

これは、元のケーキの拡張と考えることができるものです。基本的には新しいレシピを作成することで抽象化を行います。いくつかの新しいステップとその他の要素があります。ただし、ブラックベリーバージョンには、元のバージョンから引き継いだいくつかの部分があります。これらは、あらゆる種類のケーキに必要な基本ステップです。まるで牛乳のように材料のように-それはすべての派生クラスにあるものです

今、あなたは材料とステップを交換したいと思っています、そしてこれらはそのケーキの新しいバージョンで定義されなければなりません。これらは新しいケーキのために定義されなければならない抽象的なメソッドです、なぜならケーキに果物があるはずですが、どれですか?今回はブラックベリーを取ります。できました。

これで、あなたはケーキを拡張し、インターフェースに従い、そこからステップと成分を抽象化しました。


1
これは、PHPに関連するあらゆるものの私のお気に入りの比較です。それは本当に理にかなっています。ありがとうございました!
cbloss793

13

すでに優れた答えのいくつかに追加するには:

  • 抽象クラスを使用すると、ある程度の実装を提供できます。インターフェースは純粋なテンプレートです。インターフェイスは機能のみを定義でき、実装することはできません。

  • インターフェースを実装するクラスは、それが定義するすべてのメソッドの実装をコミットするか、抽象的に宣言する必要があります。

  • インターフェースは、JavaのようにPHPが多重継承をサポートしないという事実を管理するのに役立ちます。PHPクラスは、単一の親のみを拡張できます。ただし、必要な数のインターフェイスを実装することをクラスに約束することができます。

  • type:実装するインターフェースごとに、クラスは対応する型をとります。どのクラスも1つ(または複数の)インターフェースを実装できるため、インターフェースは事実上、関係のない型を効果的に結合します。

  • クラスは、スーパークラスを拡張し、任意の数のインターフェースを実装できます。

    class SubClass extends ParentClass implements Interface1, Interface2 {
        // ...
    }

いつインターフェースを使用する必要があるのか​​、いつ抽象クラスを使用する必要があるのか​​説明してください。

これまで何も実装されていないテンプレートのみを提供する必要があり、そのインターフェースを実装するクラスが、それを実装する他のクラスと同じメソッドを持つようにする場合は、インターフェースを使用します。

他のオブジェクト(部分的に構築されたクラス)の基盤を作成する場合は、抽象クラスを使用します。抽象クラスを拡張するクラスは、定義/実装されたいくつかのプロパティまたはメソッドを使用します。

<?php
// interface
class X implements Y { } // this is saying that "X" agrees to speak language "Y" with your code.

// abstract class
class X extends Y { } // this is saying that "X" is going to complete the partial class "Y".
?>

抽象クラスをインターフェイスに変更するにはどうすればよいですか?

簡略化したケース/例を以下に示します。実装の詳細を取り出します。たとえば、抽象クラスを次のように変更します。

abstract class ClassToBuildUpon {
    public function doSomething() {
          echo 'Did something.';
    }
}

に:

interface ClassToBuildUpon {
    public function doSomething();
}

12

物理学の観点から:

  • 抽象クラスは「ある」関係を表します。果物があるとしましょう。よくある責任と行動を共有する果物抽象クラスがあります。

  • インターフェイスは「すべき」関係を表します。私の意見では、インターフェース(ジュニア開発者の意見です)は、アクションまたはアクションに近いものによって名前を付ける必要があります(申し訳ありませんが、単語を見つけることができません。英語のネイティブスピーカーではありません)。 IEatableとしましょう。あなたはそれが食べられることを知っています、しかしあなたはあなたが何を食べるか知りません。

コーディングの観点から:

  • オブジェクトに重複したコードがある場合、それらは共通の動作を持っていることを示しています。つまり、コードを再利用するには抽象クラスが必要になる可能性があり、インターフェイスでは実行できません。

  • もう1つの違いは、オブジェクトは必要な数のインターフェイスを実装できることですが、「ダイヤモンドの問題」のため、1つの抽象クラスしか持てません(理由はこちらをチェックしてください。http://en.wikipedia.org/wiki/ Multiple_inheritance#The_diamond_problem

たぶんいくつかのポイントは忘れてしまいますが、はっきりさせていただければと思います。

PS: "is a" / "should do"はVivek Vermaniの答えによってもたらされました。私は彼の答えを盗むつもりはありませんでした。私がそれらを気に入ったので、単に用語を再利用するためです!


2
あなたが探している言葉は食用だと思います。
Travis Weston

1
実際、私はそれを「動詞」、「実行する言葉」と信じています
Grizly

7

抽象クラスとインターフェースの技術的な違いは、すでに他の回答に正確にリストされています。オブジェクト指向プログラミングのためにコードを書く際に、クラスとインターフェースのどちらかを選択するための説明を追加したいと思います。

クラスはエンティティを表す必要がありますが、インターフェースは動作を表す必要があります。

例を見てみましょう。コンピュータモニタはエンティティであり、クラスとして表す必要があります。

class Monitor{
    private int monitorNo;
}

ディスプレイインターフェイスを提供するように設計されているため、機能はインターフェイスで定義する必要があります。

interface Display{
    void display();
}

他の回答で説明されているように、他にも考慮すべきことがたくさんありますが、これはコーディング中にほとんどの人が無視する最も基本的なことです。


2
PHPは戻り値の型を定義せず、OPはこの質問にタグを付けましたPHP
Purefan

1

両方を使用する必要がある場合の例を追加したかっただけです。現在、汎用ERPソリューションでデータベースモデルにバインドされたファイルハンドラーを作成しています。

  • 標準のクラッドを処理する複数の抽象クラスと、さまざまなカテゴリのファイルの変換やストリーミングなどのいくつかの特殊機能があります。
  • ファイルアクセスインターフェイスは、ファイルを取得、保存、削除するために必要な共通のメソッドセットを定義します。

このようにして、異なるファイル用の複数のテンプレートと、明確に区別されたインターフェースメソッドの共通セットを用意します。このインターフェースは、基本の抽象クラスの場合とは異なり、アクセスメソッドに類似しています。

将来、さまざまなファイルストレージサービス用のアダプタを作成するときに、この実装により、インターフェイスをまったく異なるコンテキストで他の場所で使用できるようになります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.