回答:
Goslingはextendsキーワードの使用を避けるとは言いませんでした...コードの再利用を実現する手段として継承を使用しないと言いました。
継承自体は悪くなく、オブジェクト指向構造の作成に使用する非常に強力な(必須の)ツールです。(何かのために使用されたときに正しく使用しないときしかし、他のオブジェクト構造を作成するよりも)それは非常に緊密に結合し、維持することは非常に困難であるコードを作成します。
ポリモーフィック構造の作成には継承を使用する必要があるため、インターフェイスでも同じように簡単に実行できます。したがって、オブジェクト構造を設計するときにクラスではなくインターフェイスを使用することを宣言します。あるオブジェクトから別のオブジェクトにコードをコピーアンドペーストすることを回避する手段として拡張機能を使用していることに気付いた場合は、おそらく間違って使用している可能性があり、この機能を処理し、代わりにコンポジションを介してそのコードを共有するための特別なクラスを使用する方が良いでしょう。
Liskov Substitution Principleを読んで理解してください。クラス(またはその点でインターフェース)を拡張しようとするときはいつでも、原則に違反しているかどうかを自問してください。そうであれば、不自然な方法で継承を使用する可能性が最も高くなります。それは簡単であり、多くの場合正しいことのように思えますが、コードの保守、テスト、および進化がより困難になります。
オブジェクト指向プログラミングの初期の頃、実装の継承はコードの再利用の黄金のハンマーでした。あるクラスに必要な機能がある場合、やるべきことはそのクラスから公に継承することでした(これらはC ++がJavaより普及していた時代でした)。
ただし、実際には無料ではありませんでした。その結果、処理が困難なダイヤモンド型の継承ツリーを含む、理解がほとんど不可能な非常に複雑な継承階層が作成されました。これは、Javaの設計者がクラスの多重継承をサポートしないことを選択した理由の一部です。
ゴスリングのアドバイス(および他の声明)は、かなり深刻な病気に対する強力な薬であり、一部の赤ちゃんが風呂水で投げ出された可能性があると述べています。継承を使用して、クラス間の関係を真にモデル化することに何の問題もありませんis-a
。ただし、別のクラスの機能を使用するだけの場合は、最初に他のオプションを調べた方が良いでしょう。
相続は最近非常に恐ろしい評判を集めています。回避する理由の1つは、「継承に対する構成」の設計原則に沿ったものです。これは基本的に、コードの記述を節約するために、それが本当の関係でない場合は継承を使用しないことを推奨します。この種の継承により、バグの発見と修正が困難になる場合があります。あなたの友人がおそらく代わりにインターフェースを使用することを提案していた理由は、インターフェースが分散APIに対してより柔軟で保守可能なソリューションを提供するためです。多くの場合、ユーザーのコードを壊すことなくAPIに変更を加えることができます。クラスを公開すると、ユーザーのコードが壊れることがよくあります。.Netでのこれの最良の例は、ListとIListの使用の違いです。
1つのクラスしか拡張できないのに対し、多くのインターフェイスを実装できるためです。
私はかつて、継承があなたが何であるかを定義すると聞いたが、インターフェイスはあなたが果たすことができる役割を定義する。
インターフェイスは、ポリモーフィズムのより良い使用も可能にします。
それが理由の一部かもしれません。
私もこれを教えられており、可能な場合はインターフェースを好みます(もちろん、意味のある場所では継承を使用します)。
私が考えていることの1つは、コードを特定の実装から切り離すことです。ConsoleWriterというクラスがあり、それをメソッドに渡して何かを書き出し、それをコンソールに書き込むとします。ここで、GUIウィンドウへの印刷に切り替えたいとします。さて、メソッドを変更するか、GUIWriterをパラメーターとして使用する新しいメソッドを作成する必要があります。IWriterインターフェースを定義することから始めて、メソッドにIWriterを取り込むようにした場合、ConsoleWriter(IWriterインターフェースを実装する)で開始し、その後GUIWriter(IWriterインターフェースも実装する)と呼ばれる新しいクラスを作成してから、渡されるクラスを切り替える必要があります。
もう1つ(C#には当てはまりますが、Javaについてはわかりません)、1つのクラスのみを拡張できますが、多くのインターフェイスを実装できます。Teacher、MathTeacher、HistoryTeacherという名前のクラスがあったとしましょう。MathTeacherとHistoryTeacherはTeacherから拡張されましたが、MathTeacherとHistoryTeacherの両方である人を表すクラスが必要な場合はどうでしょうか。一度に1つしか実行できない場合に、複数のクラスから継承しようとすると、かなり面倒になります(方法はありますが、最適ではありません)。インターフェイスを使用すると、IMathTeacherおよびIHistoryTeacherと呼ばれる2つのインターフェイスを使用し、その後、教師から拡張されてこれら2つのインターフェイスを実装する1つのクラスを作成できます。
インターフェースを使用することの1つの欠点は、時々、人々がコードを複製するのを見るということです(インターフェースを実装する各クラスの実装を作成する必要があるため)それに相当するJavaは何ですか)。
継承よりもインターフェイスを使用する最大の理由は、実装コードの分離であると考えていますが、継承は依然として非常に有用であるため、悪とは考えないでください。