質問

インターフェース これを使用すると、それを実装するクラスのメソッドを定義するコードを作成できます。ただし、これらのメソッドにコードを追加することはできません。

抽象クラス メソッドにコードを追加するだけで、同じことを行うことができます。

抽象クラスを使用して同じ目標を達成できるのであれば、なぜインターフェイスの概念が必要なのでしょうか?

これは C++ から Java までの OO 理論に関係していると言われています。これが PHP の OO の基礎となっています。この概念は Java では役に立ちますが、PHP では役に立ちませんか?これは抽象クラスにプレースホルダーが散在しないようにするための単なる方法でしょうか?何かが足りないのでしょうか?

役に立ちましたか?

解決

インターフェイスの重要な点は、クラスに複数のインターフェイスを強制的に実装できる柔軟性を提供することですが、それでも多重継承は許可されません。複数のクラスからの継承に関する問題は多岐にわたります。 ウィキペディア そのページにはそれらが非常によくまとめられています。

インターフェイスは妥協です。多重継承に関する問題のほとんどは抽象基底クラスには当てはまらないため、最近のほとんどの最新言語は多重継承を無効にしていますが、それでも抽象基底クラスのインターフェイスを呼び出し、クラスが必要なだけそれらを「実装」できるようにしています。

他のヒント

この概念は、オブジェクト指向プログラミングのあらゆる分野で役立ちます。私にとって、インターフェースは契約のようなものだと考えています。私のクラスとあなたのクラスがこのメソッド署名コントラクトに同意する限り、「インターフェイス」できます。抽象クラスに関しては、いくつかのメソッドをスタブ化する基本クラスとして認識されているため、詳細を記入する必要があります。

すでに抽象クラスがあるのに、なぜインターフェイスが必要なのでしょうか?多重継承を防ぐため (複数の既知の問題が発生する可能性があります)。

そのような問題の 1 つ:

ダイヤモンド問題」(「致命的なダイヤモンド」と呼ばれることもある)である。 死")とは、2つのクラスBとCが、次のような曖昧さを含んでいる場合である。 クラスDはBとCの両方を継承する。メソッドがある場合 BとCがオーバーライドしたAの中で、Dがオーバーライドしていない場合。 Dがどのバージョンのメソッドを継承しているか:Bのものですか、それともCのものですか?

ソース: https://en.wikipedia.org/wiki/Multiple_inheritance#The_diamond_problem

インターフェイスを使用する理由/いつ使用するか?例...世界中のすべての車は同じインターフェース(メソッド)を持っています... AccelerationPedalIsOnTheRight(), BrakePedalISOnTheLeft(). 。各自動車ブランドが他のブランドとは異なるこれらの「方法」を持っていると想像してください。BMW はホイールの右側にブレーキを備え、ホンダはホイールの左側にブレーキを備えます。人々は、別のブランドの車を購入するたびに、これらの「方法」がどのように機能するかを学ばなければならないでしょう。そのため、複数の「場所」に同じインターフェイスを用意することをお勧めします。

インターフェイスはあなたにとって何をしますか? (なぜインターフェイスを使用するのでしょうか)?インターフェイスは、「間違い」を防ぐものです (特定のインターフェイスを実装するすべてのクラスが、そのインターフェイス内にあるメソッドを持つことを保証します)。

// Methods inside this interface must be implemented in all classes which implement this interface.
interface IPersonService
{   
    public function Create($personObject);
}

class MySqlPerson implements IPersonService
{
    public function Create($personObject)
    {
        // Create a new person in MySql database.
    }
}

class MongoPerson implements IPersonService
{
    public function Create($personObject)
    {
        // Mongo database creates a new person differently then MySQL does. But the code outside of this method doesn't care how a person will be added to the database, all it has to know is that the method Create() has 1 parameter (the person object).
    }
}

このようにして、 Create() メソッドは常に同じように使用されます。を使用しているかどうかは関係ありません。 MySqlPerson クラスまたは MongoPerson クラス。メソッドの使用方法は変わりません (インターフェイスは変わりません)。

たとえば、次のように使用されます (コード内のあらゆる場所で)。

new MySqlPerson()->Create($personObject);
new MongoPerson()->Create($personObject);

こうすれば、次のようなことは起こりません。

new MySqlPerson()->Create($personObject)
new MongoPerson()->Create($personsName, $personsAge);

複数の異なるインターフェイスよりも、1 つのインターフェイスを覚えてどこでも同じインターフェイスを使用する方がはるかに簡単です。

このように、内部は、 Create() このメソッドを呼び出す「外部」コードに影響を与えることなく、クラスごとにメソッドを変えることができます。外部コードが知っておく必要があるのは、メソッドが Create() パラメータが 1 つあります ($personObject)、それが外部コードがメソッドを使用/呼び出す方法だからです。外部コードはメソッド内で何が起こっているかを気にしません。必要なのは、その使用方法/呼び出し方法を知っていることだけです。

インターフェースを使用せずにこれを行うこともできますが、インターフェースを使用すると「より安全」になります (間違いを防ぐことができるため)。インターフェイスは、メソッドが Create() インターフェイスを実装するすべてのクラスで同じシグネチャ (同じ型と同じ数のパラメータ) を持ちます。こうすることで、 IPersonService インターフェースにはメソッドがあります Create() (この例では) 必要なパラメータは 1 つだけです ($personObject) 呼び出される/使用されます。

インターフェイスを実装するクラスは、インターフェイスが実行する/備えているすべてのメソッドを実装する必要があります。

あまり同じことを繰り返さないことを願っています。

私にとって、インターフェイスと抽象クラスの使用の違いは、言語自体による強制ではなく、コードの編成に関係しています。私は、他の開発者が作業するコードを準備するときに、意図した設計パターン内に収まるようにこれらをよく使用します。インターフェイスは一種の「契約による設計」であり、アクセス権のないコードからの API 呼び出しの規定セットにコードが応答することに同意します。

抽象クラスからの継承は「である」関係ですが、それが常に必要なわけではなく、インターフェイスの実装は「あるように動作する」関係に近いものになります。この違いは、特定の状況では非常に重要になる可能性があります。

たとえば、抽象クラス Account があり、そこから他の多くのクラス (アカウントの種類など) が拡張されているとします。これには、そのタイプ グループにのみ適用できる特定のメソッド セットがあります。ただし、これらのアカウント サブクラスの一部は、Versionable、Listable、または Editable を実装しているため、これらの API を使用することを想定しているコントローラーにスローできるようになります。コントローラーはオブジェクトの種類を気にしません。

対照的に、Account から拡張しないオブジェクト、たとえば User 抽象クラスを作成し、Listable と Editable を実装することもできますが、Versionable は実装できませんが、これはここでは意味がありません。

このように、FooUser サブクラスはアカウントではないが、編集可能オブジェクトのように機能すると言っているのです。同様に、BarAccount は Account から拡張されますが、User サブクラスではなく、Editable、Listable、および Versionable を実装します。

Editable、Listable、Versionable のこれらすべての API を抽象クラス自体に追加すると、乱雑で見苦しくなるだけでなく、Account と User の共通インターフェイスが複製されるか、おそらく単にユーザー オブジェクトに Versionable を実装するよう強制されることになります。例外。

インターフェイスは基本的に、作成できるものの青写真です。クラスにどのようなメソッドがあるかを定義します 持つ必要があります, ただし、これらの制限の外に追加のメソッドを作成できます。

メソッドにコードを追加できないという意味がわかりません。追加できるからです。インターフェイスを抽象クラスに適用していますか、それともそれを拡張したクラスに適用していますか?

抽象クラスに適用されるインターフェイス内のメソッドは、その抽象クラスに実装する必要があります。ただし、そのインターフェイスを拡張クラスに適用すると、メソッドは拡張クラスに実装するだけで済みます。ここで私は間違っている可能性があります - 私はインターフェースをできる限り頻繁に使用しません/そうすべきです。

私は常に、インターフェイスを外部開発者向けのパターン、または物事が正しいことを確認するための追加のルールセットとして考えてきました。

PHP でインターフェイスを使用します。

  1. 実装を非表示にするには、オブジェクトのクラスへのアクセス プロトコルを確立し、そのオブジェクトを使用したすべての場所をリファクタリングせずに、基になる実装を変更します。
  2. 型をチェックするには - パラメータが特定の型であることを確認する場合など $object instanceof MyInterface
  3. 実行時にパラメータチェックを強制するには
  4. 複数の動作を 1 つのクラスに実装するには (複合型を構築する)

    class Car は EngineInterface、BodyInterface、SteeringInterface を実装します {

それで、 Car オブジェクトは今 start(), stop() (エンジンインターフェース) または goRight(),goLeft() (ステアリングインターフェース)

その他、今は思いつかないこと

4 番目は、おそらく抽象クラスでは対処できない最も明白なユースケースです。

Java で考えるより:

インターフェイスとは、「このインターフェイスを実装したクラスは、こうなる」というものだ。 したがって、特定のインターフェイスを使うコードは、そのインターフェイスに対してどのメソッドが呼び出せるかを知っている。したがって、インターフェイスはクラス間の「プロトコル」を確立するために使用されます。

インターフェイスは、クラスが拡張できるベースとしてではなく、必要な機能のマップとして存在します。

以下は、抽象クラスが適合しないインターフェイスの使用例です。
ユーザーが外部ソースからカレンダー データをインポートできるカレンダー アプリケーションがあるとします。各タイプのデータ ソース (ical、rss、atom、json) のインポートを処理するクラスを作成します。これらの各クラスは、アプリケーションがデータを取得するために必要な共通のパブリック メソッドをすべて持つことを保証する共通のインターフェイスを実装します。

<?php

interface ImportableFeed 
{
    public function getEvents();
}

その後、ユーザーが新しいフィードを追加すると、そのフィードのタイプを識別し、そのタイプ用に開発されたクラスを使用してデータをインポートできます。特定のフィードのデータをインポートするために作成された各クラスは、完全に異なるコードを持つことになります。そうでない場合、アプリケーションがそれらを使用できるようにするインターフェイスを実装する必要があるという事実を除けば、クラス間の類似点はほとんどない可能性があります。抽象クラスを使用する場合は、 getEvents() メソッドをオーバーライドしていないという事実を簡単に無視できます。これにより、このインスタンスでアプリケーションが中断されてしまいますが、インターフェイスを使用すると、いずれかのメソッドが使用されない場合にアプリケーションが実行されなくなります。インターフェースで定義されたものは、それを実装したクラスには存在しません。私のアプリは、フィードからデータを取得するためにどのクラスを使用するかを気にする必要はありません。データを取得するために必要なメソッドが存在することだけを考慮する必要があります。

これをさらに一歩進めると、別のフィード タイプを追加する目的でカレンダー アプリに戻ったときに、このインターフェイスが非常に便利であることがわかります。ImportableFeed インターフェイスを使用すると、このインターフェイスを実装する新しいクラスを追加するだけで、さまざまなフィード タイプをインポートするクラスを追加し続けることができます。これにより、コア アプリケーションに不必要に大量の機能を追加することなく、大量の機能を追加できるようになります。コア アプリケーションは、インターフェイスに必要なパブリック メソッドが存在することにのみ依存しているため、新しいフィード インポート クラスが ImportableFeed インターフェイスを実装している限り、所定の位置にドロップして動き続けることができることを知っています。

これは非常に簡単なスタートです。次に、クラスが処理するフィード タイプに固有のより多くの機能を提供する、すべてのカレンダー クラスに実装を要求できる別のインターフェイスを作成できます。もう 1 つの良い例は、フィードの種類などを確認する方法です。

これは質問の範囲を超えていますが、上記の例を使用したため、次のようになります。この方法でインターフェイスを使用すると、インターフェイス自体に一連の問題が発生します。実装されたメソッドから返される出力がインターフェイスと一致するようにする必要があることがわかりました。これを実現するには、PHPDoc ブロックを読み取る IDE を使用し、インターフェイスの PHPDoc ブロックに戻り値の型を型ヒントとして追加します。それを実装する具体的なクラスに変換します。このインターフェイスを実装するクラスからのデータ出力を消費するクラスは、少なくとも、この例で返される配列を期待していることを認識します。

<?php
interface ImportableFeed 
{
    /**
     * @return array
     */
    public function getEvents();
}

抽象クラスとインターフェイスを比較する余地はあまりありません。インターフェイスは、実装時にクラスに一連のパブリック インターフェイスが必要となる単なるマップです。

インターフェイスは、開発者が特定のメソッドを確実に実装できるようにするためだけのものではありません。これらのクラスには特定のメソッドがあることが保証されているため、クラスの実際の型がわからなくてもこれらのメソッドを使用できるという考え方です。例:

interface Readable {
  String read();
}

List<Readable> readables; // dunno what these actually are, but we know they have read();
for(Readable reader : readables)
  System.out.println(reader.read());

多くの場合、抽象クラスであろうとなかろうと、基本クラスを提供することは意味がありません。実装は大きく異なり、いくつかのメソッド以外には共通点がないからです。

動的型付け言語には、インターフェイスを必要としない「ダックタイピング」の概念があります。オブジェクトに呼び出しているメソッドがあると仮定するのは自由です。これにより、オブジェクトに何らかのメソッド (この例では read()) があるものの、インターフェイスが実装されていない静的型付け言語の問題が回避されます。

私の意見では、非機能的な抽象クラスよりもインターフェイスの方が優先されるべきです。2 つのオブジェクトを解析して結合するのではなく、インスタンス化されるオブジェクトは 1 つだけなので、パフォーマンスが低下したとしても驚かないでしょう (ただし、内部の仕組みに詳しくないので確信は持てません) OOP PHP の)。

確かに、インターフェイスは Java などに比べて有用性や意味が劣ります。一方、PHP6 では、戻り値の型ヒントなど、さらに多くの型ヒントが導入される予定です。これにより、PHP インターフェイスに何らかの価値が追加されるはずです。

先生:インターフェイスは従う必要があるメソッドのリスト (API を考えてください) を定義しますが、抽象クラスはいくつかの基本/共通機能を提供し、サブクラスは特定のニーズに合わせてこれを改良します。

この点で PHP が異なるかどうかは覚えていませんが、Java では複数のインターフェイスを実装できますが、複数の抽象クラスを継承することはできません。PHP も同じように動作すると思います。

PHP では、カンマで区切ることで複数のインターフェースを適用できます (これはきれいな解決策ではないと思います)。

複数の抽象クラスについては、複数の抽象クラスを相互に拡張することができます (これについても完全にはわかりませんが、以前にどこかで見たような気がします)。拡張できないのは最終クラスだけです。

インターフェイスはコードのパフォーマンスを向上させるなどの効果はありませんが、コードを保守しやすくするのに大いに役立ちます。確かに、抽象クラス (または非抽象クラス) を使用してコードへのインターフェイスを確立できることは事実ですが、適切なインターフェイス (キーワードを使用して定義し、メソッド シグネチャのみを含むインターフェイス) の方が単純に簡単です。整理して読んでください。

そうは言っても、私はクラスよりもインターフェイスを使用するかどうかを決定する際に慎重になる傾向があります。デフォルトのメソッド実装や、すべてのサブクラスに共通する変数が必要な場合があります。

もちろん、複数のインターフェイスの実装に関する指摘も正しいです。複数のインターフェイスを実装するクラスがある場合、そのクラスのオブジェクトを同じアプリケーション内で異なる型として使用できます。

ただし、あなたの質問が PHP に関するものであるという事実は、事態をもう少し興味深いものにします。PHP では、インターフェイスへの入力は依然として驚くほど必要ではありません。PHP では、型に関係なく、あらゆるメソッドにほぼすべてのものをフィードできます。メソッドのパラメータを静的に入力することはできますが、その一部は壊れています (String はいくつかの問題を引き起こすと思います)。これを、他のほとんどの参照を入力できないという事実と組み合わせると、PHP で静的型付けを強制しようとしてもあまり意味がありません (この時点で)。そのため、インターフェイスの価値は PHPで, この時点で より強く型付けされた言語よりもはるかに少ないです。読みやすいという利点がありますが、それ以外にはほとんど利点がありません。実装側でメソッドを宣言して本体を与える必要があるため、複数の実装はメリットさえありません。

インターフェースは遺伝子のようなものです。

抽象クラスは実際の親のようなものです。

それらの目的は継承されますが、抽象クラスとインターフェイスの場合、継承される内容はより具体的です。

PHPインターフェースのポイントは以下の通りです

  1. これは、クラスに必要なメソッドの数を定義するために使用されます [HTML をロードする場合は ID と名前が必要なので、この場合インターフェイスには setID と setName が含まれます]。
  2. インターフェイスは、定義されているすべてのメソッドをクラスに含めるように厳密に強制します。
  3. パブリック アクセシビリティを持つインターフェイスでのみメソッドを定義できます。
  4. クラスのようにインターフェイスを拡張することもできます。extends キーワードを使用して PHP でインターフェイスを拡張できます。
  5. 複数のインターフェースを拡張します。
  6. 2 つのインターフェイスが同じ名前で機能を共有する場合、2 つのインターフェイスを実装することはできません。エラーがスローされます。

コード例:

interface test{
    public function A($i);
    public function B($j = 20);
}

class xyz implements test{
    public function A($a){
        echo "CLASS A Value is ".$a;
    }
    public function B($b){
        echo "CLASS B Value is ".$b;
    }
}
$x = new xyz();
echo $x->A(11);
echo "<br/>";
echo $x->B(10);

抽象クラスとインターフェイスは、子クラスに実装する必要がある抽象メソッドを提供するという点で似ていることがわかりました。ただし、次のような違いがあります。

1.インターフェイスには抽象メソッドと定数を含めることができますが、具体的なメソッドと変数を含めることはできません。

2.インターフェイス内のすべてのメソッドは、 公共 視認性 の範囲にある。

3.クラスは複数のインターフェイスを実装することができます。 1つの抽象クラスだけから。

                                  interface                      abstract class
the code                     - abstract methods               - abstract methods
                             - constants                      - constants                  
                                                              - concrete methods
                                                              - concrete variables

access modifiers             
                             - public                         - public
                                                              - protected
                                                              - private
                                                                etc.
number of parents          The same class can implement
                           more than 1 interface              The child class can 
                                                              inherit only from 1 abstract class

これが誰の理解にも役立つことを願っています!

他の言語については知りませんが、そこでのインターフェイスの概念は何ですか。ただし、PHP については、頑張って説明します。しばらくお待ちください。これが役に立った場合はコメントしてください。

インターフェイスは「契約」として機能し、サブクラスのセットが何を行うかを指定しますが、どのように行うかは指定しません。

ルール

  1. インターフェイスはインスタンス化できません。

  2. インターフェースにメソッドを実装することはできません。メソッドの .signature のみが含まれますが、詳細 (body) は含まれません。

  3. インターフェイスにはメソッドや定数を含めることができますが、属性は含めることはできません。インターフェイス定数には、クラス定数と同じ制限があります。インターフェイス メソッドは暗黙的に抽象です。

  4. インタフェースはクラスレベルの実装の詳細であるため、コンストラクタまたはデストラクタを宣言しては なりません。
  5. インターフェイス内のすべてのメソッドはパブリック可視性を持つ必要があります。

例を挙げてみましょう。2 つのおもちゃがあるとします。1 人は犬、もう 1 人は猫です。

ご存知のように、犬は吠え、猫は鳴きます。これら 2 つは同じ speech メソッドを持ちますが、機能や実装が異なります。発話ボタンのあるリモコンをユーザーに渡しているとします。

ユーザーが話すボタンを押すと、おもちゃは犬か猫か関係なく話す必要があります。

実装が異なるため、これは抽象クラスではなくインターフェイスを使用するのに適したケースです。なぜ?覚えて

非抽象メソッドを追加して子クラスをサポートする必要がある場合は、抽象クラスを使用する必要があります。それ以外の場合は、インターフェイスを選択することになります。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top