3

複数回実装されるデータ構造を設計する必要があり、問題が発生しました。

私のデータ構造には複数のバージョンが必要なので、すべての実装の基礎となる抽象クラスを作成しました。ただし、データ構造には特定のパーツのセットビューも必要です。

問題は次のようになります。セットには、データ構造の実装に応じて異なる実装が必要です: HashSet または Collections.SingletonSet のいずれかです。次に、2 つの実装データ構造は、アイテムがセットに追加またはセットから削除されたときに、これらのビットを拡張して追加のタスクを実行します。ただし、抽象的なデータ構造には、この余分な作業が行われないように、このセットから要素を内部的に削除する方法も必要です。このために、保護されたメソッドをセットに追加したいのですが、できません!

説明のために、作成しているデータ構造のタイプに関連するサンプル コードを次に示します。

public abstract class AbstractEdge {
    public abstract AbstractSetView destination(); //Gives a subclass of AbstractSetView in implementations.

    public void doStuff() {
        destination().removeInternal(foo);
    }

    public abstract class AbstractSetView implements Set<Vertex> {
        protected abstract void removeInternal(Vertex vert);
    }
}

public class Edge extends AbstractEdge {
    public SetView destination() {
        return new SetView();
    }

    public class SetView extends AbstractSetView,Collections.SingletonSet<Vertex> { //Doesn't work this way.
        protected void removeInternal(Vertex vert) {
            //Do stuff.
        }
    }
}

public class HyperEdge extends AbstractEdge {
    public SetView destination() {
        return new SetView();
    }

    public class SetView extends AbstractSetView,HashSet<Vertex> { //Doesn't work this way.
        protected void removeInternal(Vertex vert) {
            //Do stuff.
        }
    }
}

これらは私が検討したオプションです:

  • 上記のように、複数のクラスからの拡張は許可されていません。
  • AbstractSetView をインターフェースにすると、removeInternal() メソッドが公開されますが、これは望ましくありません。
  • SetView を AbstractSetView のみ拡張し、すべてを自分で実装するようにします... 2 回。しかし、これには基本的に HashSet と SingletonSet の実装を内部クラスとして含める必要があり、これは非常に見苦しいものです。

Java の設計者は、組み込みの Set 実装を使用できるようにするために、これを回避する方法を作ったのでしょうか? 私は何を見落としていますか?

4

2 に答える 2

2

いいえ、障害、問題、または制限が見られなかったので、彼らは「これを回避する」ことはしませんでした。彼らによると、実際に対応するのがコンポジションである場合、少なくとも85%の時間で多重継承が使用されるため、言語では多重継承は実際には必要ありませんでした。残りのケースの 14% はインターフェイスと構成の非自然な使用によって解決でき、1% はコードの複製によって解決できます。真: 後者は醜い、冗長で安全でないなどですが、主な目的は、組み込みデバイスでも実装できる小さな言語を作成することでした。わずか 1% のケースで、彼らはこれを諦めませんでした。私見、彼らはパーセンテージでほぼ正しかった.

2 番目の質問に答えるには、特にライブラリ クラスから継承しないでください。本当に必要なのは構成です。サブクラスによって異なる実装で初期化さAbstractEdgeれるメンバーを持つようにします。これは、およびそのサブクラスが必要ないことを意味します。protected Set backingSet;SetAbstractSetView

それ以外の場合、メンバーprotected Set backingSet;は に配置できますAbstractSetView

于 2013-08-29T23:55:37.157 に答える
0

これまでに与えられた 2 つの回答は、どちらも Set ケースの解決策とアドバイスを提供します。ただし、これおよび他の同様の状況 (たとえば、JRE クラスを拡張するのではなく、独自のものを拡張する場合) で使用できるパターンは、インターフェイスを public と内部の保護されたものに分割することです。

この場合、パブリック インターフェイスは Set になります。

保護された内部インターフェイスは、AbstractEdge 内で宣言され、removeInternal メソッドを定義する InternalSet になります。メソッドは「パブリック」になりますが、インターフェイスはそうである必要はありません。

次に、抽象スーパークラスは、サブクラスの外部で使用するパブリック インターフェイスを返すパブリック メソッドと、内部使用のみの保護されたインターフェイスを返す保護されたメソッドを定義する必要があります。

サブクラスを実装すると、クラスを実装し、必要な Set を拡張し、保護されたクラスを実装して、両方のメソッドからそのインスタンスを返すことができます。

構成するか、JRE クラスから継承するかの選択はすべてあなた次第です。

于 2013-08-30T00:12:04.287 に答える