1

派生クラスについて知っている基本クラスでメソッドを作成することは、オブジェクト指向プログラミングの良い方法ですか?

たとえば、クラス B が A から継承し、クラス C と D が B から継承するクラス A、B、C、D を考えます。ここで、A から継承するすべてのクラス (A 自体を含む) に共通のメソッドを考えます。動作するためにクラス B について知っておく必要があります (例: オブジェクト B からクラス A/B/C/ または D のオブジェクトの相対距離)。このメソッドはすべてのクラス (A、B、C、D) に共通であるため、クラス A 内に配置する必要があるのは当然のことのように思えます。ただし、この場合、派生を「認識する」基本クラスにメソッドがあります。クラス。

例:

Class A {
# simple coordinate system
    distance_to_complex_coordinate_system (B complexCoord) {
         return complexCoord.distance_to_simple_coord_system(self)
    }

}

Class B extends A {
# complex coordinate system
    distance_to_simple_coordinate_system (simpleCoord) {
         # do calculations
    }

}

Class C extends A {}
Class D extends A {}
...

上記の例distance_to_complex_coordinate_systemは、すべての単純な座標系 (つまり、A、B、C、および D) が持つべきメソッドであり、実装はそれらすべてでまったく同じです。これは抽象クラスではないため、オーバーライドしないでください。

これは OO の観点から理にかなっていますか?もしそうなら、それは本当に良いプログラミングの実践ですか? そうでない場合は、これを回避する方法についての提案をいただければ幸いです。

私の観点では、それは良い習慣ではありませんが、コードを不必要に複製せずに回避する良い方法を見つけることができません. ところで、おそらく重要ではありませんが、私は Perl を使用しています。

4

3 に答える 3

1

あなたは正しいです、サブクラスの実装について知る必要があるAのメソッドを持っているのは悪いにおいがします。おそらく、この機能を別のクラス(継承階層ではない)に分解し、この場合は継承よりも構成を優先する必要があります。

コードについて詳しく知らずに何をすべきかを確実に言うのは少し難しいです。@Styxxyは、これを回避する方法として抽象メソッドを使用することについて良い点を提起しますが、それはすべて、「AはBについて知る必要がある」と言うときの意味によって異なります。

オブジェクトがとしてインスタンス化されている場合、話している実装を取得するためにA、どのようにオブジェクトをにキャストダウンできますか?Bできません。

ただし、オブジェクトが作成された場合、そのサブクラスによってオーバーライドされる抽象メソッドを呼び出すB共通メソッドを呼び出すことができます(例)。これは大まかにデザインパターンが行うことです。親クラスは、実行するいくつかのステップとそれらのステップの順序を定義しますが、実装をサブクラスに延期します。ABTemplateA

abstract class A {
    public void doStuff() {
        doThis();
        doThat();
    }

    abstract void doThis();

    abstract void doThat();
}

class B extends A {
    @Override
    void doThis() {
        // implementation
    }

    @Override
    void doThat() {
        // implementation
    }
}


// from somewhere in code...your subclass B knows doThis() will be called before doThat()
B b = new B();
b.doStuff();

ここで正確性を検証していない構文エラーを許してください。

于 2012-05-21T21:40:49.260 に答える
1

あなたの質問の最近の説明に基づく代替ソリューション。

Bクラスの機能は、ヘルパー クラス (コンポジション) に分割する必要があると思います。Bdistance_to_simple_coord_system() の計算方法を知るには不可欠であると述べました。Bクラス階層から削除できますか?

A は B のインスタンスを所有していますが、それはもはやサブクラスではありません。B のインスタンスを実際に作成して設定する方法は、あなた次第です。

class A {
    B b = new B();

    distance_to_complex_coordinate_system() {
         // i'm guessing that passing "this" maybe of use to you
         b.distance_to_simple_coord_system(this);
    }
}

class B {  // does not extend A
    Public distance_to_simple_coord_system(A a) {}
}
class C extends A {}
class D extends A {}

[編集]

コメントに続いて...

仰るとおりです。ここで感じていないのは、すべての階層のクラスBへの依存であり、親クラスではないということです。これは OO 設計にとって根本的に間違っており、このクラスから共有機能を削除する必要があります。A

注: オブジェクト指向の設計は、10 年前の教科書で信じられていることとは対照的に、現実世界の具体的な継承階層に適していないことがあります。

このソリューションでは、A、B、C、D の階層を必要なビットだけ保持することができます。また、インターフェイスを使用してから共有機能Bを分割します。

class A {
    Calc calc = new SimpleCalc();

    distance_to_complex_coordinate_system() {
         getCalc().distance_to_simple_coord_system(this);
    }

    Calc getCalc() {
        return this.calc;
    }
}

class B extends A {}
class C extends A {}
class D extends A {}

interface Calc {
    distance_to_simple_coord_system(A a);
}

class SimpleCalc implements Calc {
    distance_to_simple_coord_system(A a) {
        // implementation assuming you don't need an "instanceof B" passed in
    }
}

Q: インターフェイスを使用する理由は何ですか?

A: クラス A、B、C、または D に基づいて計算を行う方法について、実行時に実装を決定できるようにするためです。

Cdistance_to_complex_coordinate_system を計算する別の方法が必要になる可能性があることを考慮してください。これを行うことができます...

   /*
    * Calculator specific to C
    */
    class CalcForC implements Calc {
        distance_to_simple_coord_system(C c) {
            // implementation specific to "C"
        }
    }

    class C extends A {
        Calc calcForC = new Calc();

        /* override */
        Calc getCalc() {
            return this.calcForC;
        }
    }

    C c = new C();
    c.distance_to_complex_coordinate_system();      // defined on A but calls getCalc() on C
于 2012-05-21T23:50:34.773 に答える
0

それが A の適切なコンテキストでもメソッドであるが、A で実装できない場合は、abstract派生クラスによって実装する必要があるメソッドとして宣言できます。(または、A についてのみ知っている実装を持つこともできますがoverride、派生クラスでは可能です。) クラス間の知識が多く必要であると感じている場合は、十分に抽象化されていない可能性があります。

于 2012-05-21T21:27:02.637 に答える