「記憶にとって恐ろしい」議論は完全に間違っていますが、客観的には「悪い習慣」です。クラスから継承する場合、関心のあるフィールドとメソッドだけを継承するのではなく、すべてを継承します。あなたが役に立たなくても、それが宣言するすべてのメソッド。そして最も重要なことは、すべてのコントラクトを継承し、クラスが提供することを保証することです。
頭字語SOLIDは、優れたオブジェクト指向設計のためのヒューリスティックを提供します。ここで、I nterface分掌の原則(ISP)とL置換Pricinple iskov(LSP)は、言いたいことがあります。
ISPは、インターフェイスをできるだけ小さくするように指示しています。しかし、から継承するArrayList
ことにより、多くのメソッドを取得できます。それは意味のあることですget()
、remove()
、set()
(置き換え)、またはadd()
特定のインデックスの子ノードは、(挿入)?ensureCapacity()
基礎となるリストにとって賢明ですか?sort()
ノードにとってそれはどういう意味ですか?クラスのユーザーは本当にを取得することになっていsubList()
ますか?不要なメソッドを非表示にできないため、唯一の解決策は、ArrayListをメンバー変数として使用し、実際に必要なすべてのメソッドを転送することです。
private final ArrayList<Node> children = new ArrayList();
public void add(Node child) { children.add(child); }
public Iterator<Node> iterator() { return children.iterator(); }
ドキュメントにあるすべてのメソッドが本当に必要な場合は、LSPに進むことができます。LSPは、親クラスが予想される場所であればどこでもサブクラスを使用できる必要があることを示しています。関数がArrayList
パラメータを受け取り、Node
代わりに渡す場合、何も変更されることはありません。
サブクラスの互換性は、型シグネチャなどの単純なものから始まります。メソッドをオーバーライドする場合、親クラスで有効な使用を除外する可能性があるため、パラメーターの種類をより厳密にすることはできません。しかし、それはコンパイラがJavaでチェックするものです。
しかし、LSPはさらに深く実行されます。すべての親クラスとインターフェイスのドキュメントで約束されているすべてのものとの互換性を維持する必要があります。ではその答えは、リンはそのようなケースを発見したList
(あなたが経由で継承されているインタフェースはArrayList
)どのように保証equals()
し、hashCode()
メソッドが動作するようになっているが。以下のためにhashCode()
あなたも正確に実施されなければならない特定のアルゴリズムを与えられています。あなたがこれを書いたと仮定しましょうNode
:
public class Node extends ArrayList<Node> {
public final int value;
public Node(int value, Node... children) {
this.value = Value;
for (Node child : children)
add(child);
}
...
}
これは、にvalue
貢献hashCode()
できず、影響を与えられないことを必要としますequals()
。List
インターフェース-あなたはそれから継承することによって名誉を約束する-必要がnew Node(0).equals(new Node(123))
真実であることを。
クラスから継承すると、親クラスが作成した約束を誤って破りやすくなり、通常は意図したよりも多くのメソッドを公開するため、継承よりも合成を好むことが一般的に推奨されます。何かを継承する必要がある場合は、インターフェイスのみを継承することをお勧めします。特定のクラスの振る舞いを再利用したい場合は、インスタンス変数に別のオブジェクトとして保持することができます。そうすれば、すべての約束と要件が強制されることはありません。
時々、私たちの自然言語は相続関係を示唆しています:車は乗り物です。オートバイは乗り物です。私は、クラス定義すべきであるCar
とMotorcycle
のこと継承Vehicle
クラスを?オブジェクト指向の設計とは、実際のコードを正確にミラーリングすることではありません。ソースコードで現実世界の豊富な分類法を簡単にエンコードすることはできません。
そのような例の1つは、従業員と上司のモデリングの問題です。複数Person
のがあり、それぞれに名前と住所があります。AnがEmployee
あるPerson
と持っていますBoss
。A Boss
もPerson
です。ではPerson
、Boss
and によって継承されるクラスを作成する必要がありEmployee
ますか?今、私には問題があります。上司も従業員であり、上司がいます。だから、Boss
拡張する必要があるようEmployee
です。しかし、CompanyOwner
あるBoss
のではなくEmployee
?あらゆる種類の継承グラフが何らかの形でここで分類されます。
OOPは既存のクラスの階層、継承、再利用ではなく、動作を一般化することです。OOPとは、「オブジェクトがたくさんあるので、それらに特定のことをさせたいのですが、どうすればよいか」ということです。それがインターフェイスの目的です。繰り返し可能にしたいためにIterable
インターフェースを実装する場合Node
、それはまったく問題ありません。Collection
子ノードなどを追加/削除するためにインターフェイスを実装する場合、それで問題ありません。しかし、別のクラスから継承するのは、そうではないすべてをあなたに与えるからです。少なくとも、上で概説したように慎重な考えを与えない限り、そうではありません。