すべての Collections はCollectionインターフェースを実装し、これらのコレクションには特定の抽象階層があります。
ただし、 Collection、List、Setなどの対応するインターフェイスもあります。これらのインターフェースは、冗長に思えます。
なぜ彼らはここにいるのですか?それは単なる慣例ですか、それともインターフェースを実装するだけで抽象クラスを拡張しない理由がありますか。
すべての Collections はCollectionインターフェースを実装し、これらのコレクションには特定の抽象階層があります。
ただし、 Collection、List、Setなどの対応するインターフェイスもあります。これらのインターフェースは、冗長に思えます。
なぜ彼らはここにいるのですか?それは単なる慣例ですか、それともインターフェースを実装するだけで抽象クラスを拡張しない理由がありますか。
実装を強制せずに変数またはパラメーターに型を割り当てることができるのは良いことなので、インターフェイスが存在します。
たとえば、Hibernate で使用する永続エンティティを作成し、それがコレクションを持っている場合、それに List または Set のタイプを割り当てたいとします。Hibernate は、私が初期化したリストを独自のものに交換し、遅延読み込みを行う Hibernate 固有の実装など、必要なものをすべて使用します。Hibernate 開発者は、abstract クラスを拡張しなければならないことによる制約を望まない場合があります。
抽象クラスは、実装者の便宜のために存在します。インターフェイスは、クライアントが使用するコントラクトです。
インターフェイスの実装は、抽象クラスの拡張とは大きく異なります。
クラスAnimalが抽象クラスであり、Dog、Cat、Snake、SharkがAnimalを拡張するとします。
デフォルトのAnimal.move()実装は、単にそれらを移動します。
ただし、インターフェイスを使用すると、RunningAnimal、SwimmingAnimalなどの同様の動物をさらにグループ化できます。
したがって、DogがAnimalを拡張してRunningAnimalを実装する場合、継承されたmove()に沿って、彼自身のrun()も実装する必要があります。これは、Animalから継承されたオーバーライドされたmove()の方法である可能性があります。これはまだあなたにとって意味がありますか、それとも私はよりよく/いくつかのコードで明確にする必要がありますか?:)
インターフェイスを使用すると、さまざまなクラスの同様の機能をグループ化できます。「クリック可能」、「ソート可能」、「シリアル化可能」...これらはすべて、同じ目的ではなく、共有機能(クリック可能のリストはボタンのリストではありません)を通じてメンバーを包含します。
だから、このように考えてください
Cat extends Animal implements RunningAnimal, ClimbingAnimal -- inherits move() has to implement run() and climbTree()
Dog extends Animal implements RunningAnimal -- inherits move(), has to implement run()
Snake extends Animal -- likely overrides inherited move()
Shark extends Animal implements SwimmingAnimal -- likely overrides move(), has to implement swim()
なぜだめですか ?抽象クラスは、継承プロセスを簡素化するために作成されています。コレクションを作成する場合、すべてを最初から行う必要はありません。
しかしもちろん、AbstractCollectionから継承する必要があるとは誰も教えてくれません。実装を最初から作成できます。
これは、APIがインターフェースを持つための一般的なグッドプラクティスです。そして、実装とインターフェースを区別します。
インターフェイスは、ユーザーと実装者の間で交わされる契約です。抽象基本クラスは、同様に動作する多数のオブジェクトにアクセスするための共通の基本として使用することを目的としています。