いくつかのクラスParent
とChild1
... Child9
Javaで実装されています。 Parent
は抽象クラスであり、子クラスのすべての共通変数(多くの場合、これがParent
をインターフェイスではなく抽象クラスにした主な理由です)を含み、いくつかの抽象といくつかの実装されたメソッド。
一部の子クラスには、それらに固有のカスタムメソッドがあります。ダウンキャストを使用して子メソッドを呼び出すことがよくあります。
Parent p = new Child1();
((Child1) p).child1SpecificMethod();
どういうわけか、これはOODの悪い習慣だと感じていますが、それが本当にデザインの改善方法であるかどうかはよくわかりません。
-Edit-おそらくとにかく変更する必要があるのは、多くの(現時点では)共通変数を整理するためにParentクラスを使用し、それらを具象クラスのメンバー(またはコンテナーオブジェクト)メンバーにすることです。
これは悪い習慣だけではなく、不必要に複雑です。
なぜ一般的にinheritanceを使用するのですか?
継承を使用すると、多くの異なるキャリアで利用できるようにする共通の動作セットがあります。これにはクラス継承とals インターフェイス継承が含まれます。 相続人、いわば、多くの場合、継承元のクラスの専門化です。これは主にクラスの継承に当てはまります。
クラスcarとサブクラスporscheを考えてください(一般的なis a-relationship)。 starting/stopping engine、steeringなどの一般的な動作があります。 porscheを車のように扱う場合、その動作のこの側面に拘束されます。 porscheだけが必要で、それだけを扱うポルシェとしてであることがわかっている場合、ポルシェを-としてインスタンス化するのは冗長ですcarおよびcastingを介してporsche-behaviourを取得します。
ポリモーフィズムは、その逆の意味を持ちます。
あなたはポルシェを持っていて、車の観点からそれを扱う必要があります;例えば運転
porscheがsteer leftを受け入れる限り、steer right、shift up、shift downなど。ポリモーフィズム/置換を相互に使用できます。
オブジェクトを特殊な形式でインスタンス化することをお勧めします。そうすれば、polymorphismを最大限に活用して、-needの場合にのみ使用できます。
つまり、Parent p = new Child1();
は私には意味がありません。
編集:porscheを実装します(--compositionを介して)。ただし、例としてis a carとします。
あなたの気持ちはそれを悪い習慣だと考えるのは正しいです。あなたのサンプルコードが少し違うと想像してください:
Parent p = createObject();
((Child1) p).child1SpecificMethod();
Pの値が本当にChild1であることをどうやって知っていますか?そうしないと、実行時にClassCastExceptionが発生する可能性があります。コードでchild1SpecificMethod()を呼び出す必要がある場合は、pの型がChild1であることを確認する必要があります。 Object pがタイプParentとしてコードに(たとえばメソッドパラメーターとして)渡されるためにそれが不可能な場合は、 Visitor-Pattern のバリアントを使用して、handle-Methodでchild1SpecificMethodを実行することを検討できます。 Child1を処理するビジターオブジェクトの.
代わりに機能のルックアップを使用します。子クラスへのアクセスを許可しないで、それらを親クラスの実装と見なします。
次に、いくつかの機能、機能を指定するインターフェイスを定義します。
interface Child1Specific {
void child1SpecificMethod();
}
使用法:
Parent parent = ...
Child1Specific specific = parent.lookup(Child1Specific.class);
if (specific1 != null) {
specific1.child1SpecificMethod();
}
この検出メカニズムは非常に柔軟です。継承の代わりに委任を使用すると、かなりやりがいがあります。子クラスを持つことはもはや必要ないことに注意してください。
またはJava 8(いくつかのバリエーションが可能であり、インターフェースも機能する可能性がある場合)で:
Optional<Child1Specific> specific = parent.lookup(Child1Specific.class);
if (specific1.isPresent()) {
specific1.get().child1SpecificMethod();
}
Parentクラスで、いくつかの機能のルックアップを作成します。
public class Parent {
protected final Map<Class<?>, Object> capabilities = new HashMap<>();
protected final <T> void registerCapability(Class<T> klass, T object);
public <T> T lookup(Class<T> klass) {
Object object = capabilities.get(klass);
return object == null ? null : klass.cast(object);
}
またはJava 8:
public <T> Optional<T> lookup(Class<T> klass) {
Object object = capabilities.get(klass);
return Optional.ofNullable(klass.cast(object));
}
子クラス:
class Child1 extend Parent implements Child1Specific {
Child1() {
registerCapability(Child1Specific.class, this);
}
}
またはより動的:
class Child1 extends Parent {
private Child1Specific specific = new Child1Specific() {
... Parent.this ...
};
Child1() {
registerCapability(Child1Specific.class, specific);
}
}