4

クラス階層を設計したい。スーパークラスには抽象メソッドがあり、サブクラスはこのメソッドをオーバーライドする必要がありますが、私の問題は、このメソッドがスーパークラス (インスタンス変数) のデータを使用することです。

この問題を解決するために、いくつかのスタイルを設計しました。

スタイル 1: プライベート インスタンス変数を使用し、サブクラスで別のインスタンス変数を作成する

class SuperClass {
    private T data;

    public SuperClass(T data) { /* ... */}

    public abstract void doSomething();
}

class SubClass extends SuperClass {
    private T data; // use another variable

    public SubClass(T data) {
        super(data);
        this.data = data;
    }

    public void doSomething() {
        // use 'data'
        int length = data.getLength(); // for example...
    }
}

スタイル 2: 保護されたインスタンス変数を使用:

class SuperClass {
    protected T data;

    public SuperClass(T data) { /* ... */}

    public abstract void doSomething();
}

class SubClass extends SuperClass {
    public void doSomething() {
        // use 'data'
        int length = data.getLength(); // for example...
    }
}

スタイル 3: プライベート インスタンス変数と保護されたメソッドを使用します。

class SuperClass {
    private T data;

    public SuperClass(T data) { /* ... */}

    public abstract void doSomething();

    protected T getData() {
        return data;
    }
}

class SubClass extends SuperClass {
    public void doSomething() {
        // use 'data'
        int length = getData.getLength(); // for example...
    }
}

それらのどれがより良いですか?または、私の問題をよりよく解決するための解決策が他にありますか?

4

5 に答える 5

9

通常は 3 番目の方法が好まれ、パブリックサブクラス化を設計する場合は必須です。スーパークラスは、その内部を可能な限り制御したいと考えています。

一方、すべてが同じパッケージ内にある、または少なくともすべてが同じプロジェクト内にある閉じた階層を開発している場合、何らかの利点がある場合は、var を保護されたものとして公開することを選択できます。

ただし、サブクラスでプライベート変数を複製することは、すべての点で失敗です。それが何かに役立つシナリオは考えられません。

于 2012-07-09T19:39:02.397 に答える
1
  • Style1 : SuperClass.data と SubClass.data は 2 つの異なる変数であるため、それらが同じオブジェクトを参照するという保証はありません。
  • Style2 :これはうまく機能しますが、SubClass は SuperClass 変数の参照を変更できます。変数を null に設定できます。誰が、どのクラスが変数を更新するかは明確ではありません。
  • Style3 : SuperClass はメンバー変数へのアクセスを真にカプセル化し、制御するため、これが最善の方法だと思います。
    getData() メソッドを最終的なものにして、設計が誤用されないようにすることもできます。
于 2012-07-09T19:50:36.997 に答える
1

IMHOソリューション#1は、参照を不必要に複製し、混乱を招くため、貧弱です(メモリ消費や一貫性についてでさえありません)

解決策23は同じように有効です。dataフィールドを作成する場合final

protected final T data;

解決策2が最善です。

于 2012-07-09T19:39:24.753 に答える
1

状況によります。たとえば、最初のソリューションは、必要なデータがコンストラクターによって渡されたときにのみ使用できます。2 つ目は、フィールド自体が拡張クラスからアクセス可能であるという問題があります (そして、それらは値を変更する可能性があります)。3 つ目は、データをクラスにカプセル化するアプローチです。

  1. サブクラスのフィールドを変更する必要がある場合は、アプローチ 2 を使用できます。
  2. コンストラクターとしてデータがある場合は、アプローチ 1;
  3. 公開するだけで詳細をカプセル化する必要がある場合は、アプローチ 3.

それらは同じものではありません。

于 2012-07-09T19:39:55.787 に答える
1

最も単純なので、バージョン 2 を使用します。ただし、データを最終的にしようと思います。そうしないと、サブクラスが予期しない瞬間にデータを変更する可能性があります。

しかし、個人的な好みは別として、アプローチに大きな違いはありません。そして、何らかの関連する方法でそれらを実際に異なるものにする変更が発生した場合、一方を他方にリファクタリングするのは簡単です。

もちろん、より優れた設計 (おそらく継承がまったくないもの) がどこかに潜んでいる可能性は常にありますが、提供された情報からはわかりません。

コメントによって促される更新:

私がよく目にする 1 つの例は、ある種の戦略を実装するサブクラス (B が A を拡張する) です。このような場合、実際に戦略オブジェクトをパラメータとして A に渡し、パラメータを渡す B のメソッドを呼び出す方が理にかなっています。

于 2012-07-09T19:40:32.257 に答える