1

ジェネリックを使用して、複合階層のサブタイプを制限できるようにして、階層の異なるレイヤーで異なるタイプを強制できるようにしています。

たとえば、(Business:Division:Department:Group:Person) 階層がある場合、各レベルの複合ノードは適切なタイプ (階層内の次の下位レベル) の子ノードのみを受け入れます。したがって、次の下位レベルからのノードのみを受け入れるようにインスタンス化された各レベル タイプでジェネリックを使用して、コンポジット内のレベルを構築します。

しかし、ジェネリックでエラーが発生しました。それが設計エラーを示しているのか、それとも単に Java ジェネリックではできないことを示しているのかわかりません。アイデアは有効に思えます。構造のレベルを強制するために、階層内の特定の次のレベルからのサブタイプのみを受け入れるように add() メソッドによって受け入れられる型を制限したいだけです。各段階で型の上限を下げているだけなので、リストに送信されたすべてのメッセージは引き続き有効です。

典型的な GOF 複合パターンの最上位ノード:

   public abstract class Business { ... }

複合ノード階層の最上位:

  public abstract class Group extends Business {

    protected List<Business> subs;      // composite links
    public Group add(Business comp) {
        subs.add(comp);
        return this;
    }

複合階層の後続のレベル:

 public class Area<T extends Business> extends Group {

    protected List<Business> subs;      // composite links

    public Area(String title){
        super(title);
        subs = new ArrayList<Business>();
    }

    @Override
    public Group add(T comp) {    // ** Error Here **
        super.add(comp);
        return this;
    }

エラーは次のとおりです。

 Multiple markers at this line
    - The method add(T) of type Area<T> must override a superclass method

- 名前の衝突: タイプ Area のメソッド add(T) は、タイプ Group の add(Business) と同じ消去を持ちますが、それをオーバーライドしません

Group::add() メソッドに同様の型を指定して、同じ型シグネチャを持つようにするバリエーションを試しました。

public Group add(T comp) { ... }

しかし、それは同様に失敗します:

 Multiple markers at this line

- タイプ Area のメソッド add(T) は、スーパークラス メソッドをオーバーライドする必要があります - labs.composite.company.Group.add をオーバーライドします - 名前の衝突: タイプ Area のメソッド add(T) は、タイプの add(T) と同じ消去がありますグループ化しますが、オーバーライドしません

ここで何かが足りないのですか?ティア

PS: 実際には、このジェネリックの使用は、とにかく私が望むことを正確に行うとは思いません (たとえそれが機能したとしても!)。なぜなら、各レベルで上限を変更するだけでなく、特定の単一レベルを必要とするからです。型階層であり、共変の引数型ではありません。「 Composite のサブタイプである任意のタイプ T については、 add() メソッドでそのタイプのオブジェクトのみを受け入れます」のようなものが本当に必要ですComposite "のサブタイプです。Java の引数は共変であり、LSP では常にサブタイプの使用が許可されるため、これは不可能だと思います。

4

2 に答える 2

3

あなたの質問がエラーの理由である場合、理由は単純です: TinAreaは無限のBusinessサブクラスになる可能性がありますが、 BusinessinGroupは非常に特定のクラスです。どちらの方法も同じではありません。コンパイラは、型チェックの実行中に主に完全な型で動作します (特定の種類の警告や特殊なケースの消去も考慮する場合でも)。それがジェネリックの要点です。それ以外の場合は、ジェネリック以前のコード スタイル (まだサポートされています) に戻すことをお勧めします。

そうでなければ、私は質問を理解していません。しかし、さらにいくつかのコメントを追加さ​​せてください。

1) 継承は、「持つ」または「構成される」関係ではなく、「ある種の」関係を表します。Groupコードでは、 aは の一種でBusinessあり、 anAreaは の一種であると言っていますGroupGroup 私にとっては、a が aに属しているBusiness(つまり、aBusiness Groups を持っている)と考える方がはるかに自然です。Groups とs も同じですArea。これら 2 つの関係はいずれも継承によるものではなく、合成によるものです。

2)class Group<T extends Business>メソッドを定義するときとメソッドを定義するadd(T comp)ときclass Area<T extends Business>は、同じ署名を持っているadd(T comp)と言います。それは正しくありません。Groupのジェネリック パラメータは、In Areaから完全に独立しています。なんで?と は Business のサブクラスであると仮定しますが、お互いのサブクラスではありません。誰もそれを言うことはできず、同じ署名を持っています。実際、この同等性が成立する唯一のケースは、ジェネリック引数が同じ (つまりと) の場合です。Java は、その等価性が少数の特定のケース (コードで記述されていない場合) でのみ保持される場合、署名が等価であると見なすことができません。Group::addArea:addTTB1B2Area<B1>:add()Group<B2>:add()Area<B1>Group<B1>

3) GOF の Composite デザイン パターンは、このケースには適用されません。これは、階層的な構成を表すのではなく、「制限のない」構成と呼ぶことができるためです。このパターンによれば、aCompositeは を含むことができますdifferentComponentsが、これらのは、クラス階層の高低に関係なく、Component任意の種類の にすることができます。Compositeあなたが望むのはdifferentComponents、すぐ下のクラスになることです。それ以上でもそれ以下でもありません。

このケースを設計パターンとして見た記憶がありません。シンプルすぎるからでしょうね。次のポイント 4) の最後のバリアントを参照してください。

4) コードはおそらく次の形式を取る必要があります。

public class Grouping<C,T> {
    C curr;
    List<T> subs;
    public C add(T comp) {
        this.subs.add(comp);
        return this.curr ;
    }
}

public class Business extends Grouping<Business,Group> {
    // Grouping::add does not need to be overriden
}
public class Group extends Grouping<Group,Area> {
    // Grouping::add does not need to be overriden
}

等々。メソッドがの代わりにadd戻ることを許可する場合、すべてのクラスでジェネリック パラメータを削除できます。voidC

public class Grouping<T> {
    List<T> subs;
    public void add(T comp) {
        this.subs.add(comp);
    }
}

public class Business extends Grouping<Group> {
    // Grouping::add does not need to be overriden
}
public class Group extends Grouping<Area> {
    // Grouping::add does not need to be overriden
}

そして、それを本当にシンプルにしたい場合(ただし、それほど強力ではないかもしれません):

public class Business {
    List<Group> subs;
    public Business add(Group comp) {
        this.subs.add(comp);
        return this ;
    }
}
public class Group {
    List<Area> subs;
    public Group add(Area comp) {
        this.subs.add(comp);
        return this ;
    }
}

これにより、コードの重複 (addすべてのクラスのメソッド) が作成され、より現実的なシナリオでは、はるかに高くなる可能性があります (メソッドcountlistretrieveなども必要になる可能性があります)。

于 2013-08-16T03:55:49.250 に答える