web-dev-qa-db-ja.com

どのメソッドをインターフェイスに、どのメソッドを抽象クラスに配置する必要がありますか?

私は多くのフレームワークとモジュールを見てきました、そしてそれらが従うそれらの標準はこのようなものです

  1. UserInterfaceいくつかの定義済みメソッドがあります
  2. AbstractUserClassuserInterfaceを実装します
  3. 次に、GenericUserClassから拡張されるAbstractuserClass
  4. 次に、そのジェネリックから拡張された他のクラス

これで、抽象クラスにはインターフェースへの追加機能があり、総称クラスにも追加機能があることがわかりました。

  1. だから私はどの方法がどこに行くべきか混乱しています
  2. たまにclass A extends Abstractuserclass そして時折 class A extends Abstractuserclass implements UseraInterfaceAbstractclassがすでにUserinterfaceを実装している場合の違いは何ですか
5
user26

経験則は次のとおりです。

  • インターフェースは、公開API(契約)または特定の機能を定義します。
  • 抽象クラスは、(拡張クラスが使用するための)プライベートAPI(共有機能など)を提供します(可能性があります)。

だから私はどの方法がどこに行くべきか混乱しています

メソッドをパブリックAPIの一部にする必要がある場合は、それをインターフェースに追加し、必要に応じて依存関係を更新します(つまり、抽象クラスまたは汎用クラス、あるいはその両方)。

それ以外の場合は、一般的または具体的な方法に基づいて、必要なだけ高い方法でメソッドを実装します。

時々、クラスAがAbstractuserclassを拡張するのを見たり、クラスAがAbstractuserclassを拡張したりしてuseraInterfaceを実装するのを見ます。 AbstractclassがすでにUserinterfaceを実装している場合の違いは何ですか

その場合、違いはありません。祖先がすでにインターフェースを実装している場合は、インターフェースを2回指定する必要はありません。契約を破ろうとするとインタープリターがエラーをスローするためです。

これは、子クラスが別のインターフェースを完全に実装する場合にのみ意味があります。そして、これはインターフェースの強みです。特定の実装ではなく機能の一部を定義しているため、必要に応じて任意のクラスに任意のインターフェースを実装させることができます。これは、テスト用のモッククラスを作成する場合に非常に役立ちます。

7
Jack

インターフェースはcontract-表すオブジェクトに必要な機能を公開するAPIです。したがって、インターフェイスはそれが表す概念に関連するすべてのメソッドをサポートする必要があります。

だから私はどの方法がどこに行くべきか混乱しています

通常、インターフェースを直接実装する代わりに、抽象クラスまたは抽象汎用クラスが使用されます。これらのクラスは、ほとんどの場合、インターフェースを実装するより高速な方法として機能し、ボイラープレートコードを節約します。ジェネリックスは通常、潜在的なインターフェイスの実装のタイプセーフに対処します。彼らが新しい方法を導入することは正常です。

古典的な例は、インターフェイスを実装し、ほとんどの検証とチェックを実行する抽象クラスで、ユーザーロジックを含む必要があるいくつかの抽象メソッドを残しています。これにより、具体的な実装の定型コードのほとんどが削減され、実装されないままになっている機能が直接示されます。
通常、ジェネリッククラスはほとんどのインターフェイスを型キャストおよびチェックと共に実装し、非ジェネリックインターフェイスメソッドから呼び出される、同様の、今ではジェネリックメソッドを最終実装に残しています。

上記に加えて、基本クラスは、実装のためのコンテキスト固有のメソッド、またはインターフェースの概念に属していないように見える追加のメソッドを導入する場合があります。たとえば、架空のStreamインターフェースを使用してネットワークストリームを実装する場合、実装はネットワークの場所、URL、またはその他の接続の詳細のメソッドまたはプロパティを公開する場合があります。これらはNetworkStreamとネットワーキングコンテキストに固有であり、Stream実装もあり、何もない場合があるため、汎用MemoryStreamインターフェースでは適切ではありません。ネットワークパスで行うこと。

抽象クラスがインターフェイスに存在してはならないが存在する新しいメソッドを導入するもう1つの理由は、コードの依存関係を回避するためです。インターフェイスは、それがカバーする機能に直接関連しないライブラリの依存関係をトリガーしてはなりません。ほとんどの場合、programming to interfacesパラダイムに固執すると、実装タイプを直接操作するのではなく、インターフェースを持つライブラリを参照し、それを介してインターフェースの実装を使用します。これにより、インターフェイスを操作するときに、実装固有のライブラリへの直接参照を回避できます。

クラスAがAbstractuserclassを拡張することもあれば、クラスAがAbstractuserclassを拡張することもあり、useraInterfaceを実装しています。抽象クラスがすでにユーザーインターフェースを妨害している場合の違いは何ですか

インターフェースを指定しても、基本クラスですでに実装されていれば、違いはありません。冗長すぎるか、またはこれによりコードが読みやすくなるため、一部の人がそれを行うと思います。次のコード行を読むことで、Abstractuserclassを実行してUseraInterfaceを実装していることを確認する必要がなくなります。

class A extends Abstractuserclass implements UseraInterface

そのため、これにより多少の労力が節約され、コードは一目瞭然のコードになります。

3
Ivaylo Slavov

ここでのいくつかの回答は、interfaceが契約であることを示す非常に一般的なものです。 PHPにインターフェースとクラスのスコープがない場合、それらが契約であると言うのは難しいです。したがって、契約を強制することは不可能です。開発者がクラスをインスタンス化してインターフェースを無視するのを妨げるものは何もありません。したがって、契約の説明は、JavaまたはC++を以前に使用したことがない開発者にはそれほど明確ではありません。

それで、それはすべて何ですか?

あなたの例はあまり良いものではありません。 UserInterfaceからAbstractUserClassからGenericUserClassは、実際に起こっていることの利点を示していません。では、少し詳しく説明します。

オブジェクトが複数のインターフェースを実装できるので、なぜインターフェースがあるのですか?インターフェイスはメソッドではなく、クラスの定義済みの動作と考えてください。インターフェイスは「私はser "のように振る舞うことができます。コードがこれをどのように達成するかは問題ではありません。このインターフェースをサポートしているだけです。

優れたインターフェース設計の鍵は、多目的インターフェースを作成することではありません。各インターフェースに単一の動作を定義させます。これにより、これらの種類のオブジェクトを処理する単一目的のクラスを簡単に作成できます。 UserInterfaceを1つ持つ代わりに、AdminInterfaceAuthenticatedUserInterfaceおよびUserPermissionsInterfaceを含めるように拡張できます。したがって、コードの後半で、オブジェクトがAdminInterfaceをサポートしているかどうかを尋ねることができます。サポートしている場合、そのユーザーは管理者です。

なぜ抽象クラスがあるのですか?

インターフェース、インターフェース、どこでもインターフェース...インターフェースを使用することの欠点の1つは、インターフェースがまったくコードを実装しないことです。すべてのインターフェースについて、プログラマーは少なくとも1つのクラスを実装する必要があります。インターフェースを使用する優れたフレームワークは、それらのインターフェースを使用するための開始点を提供する、すでに実装されている幅広い抽象クラスを提供します。悪いフレームワークは、多くのインターフェースを必要とし、最初から何も提供しないものです。

多くのインターフェースを実装し、それらのインターフェースにほとんどの機能を提供するsuper抽象クラスは避けてください。また、他の多くのクラスにも大きく継承されています。

必要なのは、さまざまな視点からインターフェースを実装する小さな抽象クラスです。このUserInterfaceAbstractInvalidUserまたはAbstractAnonymousUserのようにAbstractAuthenticatedUserを実装するクラスをいくつか作成したい場合があります。後で、ユーザーのログインにFacebookを使用する必要がある場合があります。次に、FaceBookUserを拡張するAbstractAuthenticatedUserを作成できます。これで、各抽象クラスが何をするかは明らかですが、それらはすべてUserInterfaceを実装しています。

それで、「すべての方法はどこに行くのですか?」

保守可能なソースコードを作成するための鍵は、依存関係を常に最小の部分まで減らすことです。つまり、現在のユーザーの名前を表示するだけの場合は、FaceBookUserを使用してソースコードを作成する必要はありません。ソースコードのすべてがFaceBookUserを使用している場合、そのクラスを別のフォルダーに移動したり、そのクラスの名前を変更することは困難です。 UserInterfaceを使用してユーザー名を表示する方が簡単です。これで、すべてのソースコードは、それがFacebook、Google +、または自分のサインインであるかどうかを気にしません。インターフェイスがシンプルであるため、依存関係は小さく保たれ、単一の目的。

インターフェイスは、コードをインターフェイスの実装から分離するためです。他のコードは、現在のオブジェクトがラッパークラス、デリゲートクラス、スーパーヘビークラス、または単純なクラスであるかどうかを気にしません。コードが気にかける限り、それは単なるUserInterface参照です。

インターフェイスは、管理コードの作成に役立つツールです。メソッドをインターフェースに配置して、クラス間の依存関係を作成しないようにします。複数のインターフェースを作成することで、依存関係を解消します。

それは彼らがそれを契約ものと呼ぶときに人々が意味することです。

0
Reactgular