5

ShapeManagerしたい形状のリストを持つ 基本クラスがありenumerate()ます。次に、s の代わりにColoredShapeManager特殊化された s を処理したい特殊化があります。ColoredShapeShape

+----------------+      +-------------------------------------+
| Shape          |      | ShapeManager                        |
|----------------|      |-------------------------------------|
| + id: int      |      | # shapes: List<Shape>               |
|                |      |                                     |
|                |      | + ShapeManager() {                  |
|                |      |     shapes.add(new Shape());        |
|                |      |   }                                 |
|                |      |                                     |
|                |      | + abstract void enumerate() {       |
|                |      |     for (Shape s: shapes) {         |
|                |      |        // use s                     |
|                |      |     }                               |
|                |      |   }                                 |
+----------------+      +-------------------------------------+
         ^                              ^
         |                              |
         +                              +
+----------------+      +-------------------------------------+
| ColoredShape   |      | ColoredShapeManager                 |
|----------------|      |-------------------------------------|
| + color: int   |      | + ColoredShapeManager() {           |
|                |      |     shapes.add(new ColoredShape()); |
|                |      |   }                                 |
|                |      |                                     |
|                |      | + abstract void enumerate() {       |
|                |      |     for (Shape s: shapes) {         |
|                |      |       // use (ColoredShaped) s      |
|                |      |       // will fail for Shapes       |
|                |      |     }                               |
|                |      |   }                                 |
+----------------+      +-------------------------------------+

ShapeManager がその子と共有する必要があるかどうかわかりませんを処理したいshapes: List<Shape>ので、これには欠陥があるようです。したがって、要素をキャストしますが、一部の要素 (基本クラスによって追加された要素) は型であり、キャストは失敗します。ColoredShapeManager.enumerate()ColoredShapeShape

あれは:

  • 両方のタイプの形状がリストに表示されますshapes
  • enumerate()子マネージャで にアクセスできる必要がありますColoredShape

リストを分割して、2 つのマネージャーのそれぞれに非公開リストを作成する必要がありますか? 次に、子で列挙すると、「その」タイプの形状のみが反復さenumerate()れ、開始/終了で親の形状が呼び出されます。

4

6 に答える 6

6

マネージャ クラスの「型パラメータ」としてシェイプ型を追加できます。したがって、基本的にColoredShapeManagerは拡張できShapeManager<ColoredShape>、これTは内部Listデータ構造のタイプになります。また、 でColoredShapeManager特に何もColoredShapesしない場合は、新しいクラスさえ必要ないと主張します。ただし、アプリ/デザインを構築する方法によって異なります。

于 2013-01-10T09:49:13.650 に答える
3

ここでは、ビジターパターンがあなたに合っていますか?

public void doSomething(ShapeManager) {
    ...
}

ShapeManager

abstract void enumerate() {
   for (Shape shape: shapes) {
       shape.doSomething(this);
   }
}

次に、タイプを知る必要はなく、各形状の導関数は独自の実装を持つことができます。

于 2013-01-15T11:23:14.210 に答える
2

でジェネリックを使用できると思いますShapeManager。よろしければ、クラス図をお借りします。

+----------------+      +---------------------------------------+        +------------------------------+
| Shape          |      | AbstractShapeManager<S extends Shape> |        | ShapeManager<Shape>          |
|----------------|      |---------------------------------------|        |------------------------------|
| + id: int      |      | # shapes: List<S>                     |        | + Shape() {                  |
|                |      |                                       |        |     shapes.add(new Shape()); |
|                |      | + abstract void enumerate() {         | < —— + |   }                          |
|                |      |     for (S s: shapes) {               |        |                              |
|                |      |        /* use s */                    |        | + void enumerate() {         |
|                |      |     }                                 |        |     for (Shape s: shapes) {  |
|                |      |   }                                   |        |       // use Shape           |
+----------------+      +---------------------------------------+        |     }                        |
         ^                              ^                                |   }                          |
         |                              |                                +------------------------------+
         +                              +
+----------------+      +-------------------------------------+
| ColoredShape   |      | ColoredShapeManager<ColoredShape>   |
|----------------|      |-------------------------------------|
| + color: int   |      | + ColoredShapeManager() {           |
|                |      |     shapes.add(new ColoredShape()); |
|                |      |   }                                 |
|                |      |                                     |
|                |      | + void enumerate() {                |
|                |      |     for (ColoredShape s: shapes) {  |
|                |      |       // use ColoredShape           |
|                |      |     }                               |
|                |      |   }                                 |
+----------------+      +-------------------------------------+

この方法の欠点は、タイプの制限があるため、リストに Shape を追加できないことです。

于 2013-01-18T10:01:54.983 に答える
2

動作 を分離してコンテナを生成してみません?

容器:

public class ShapeManager<T extends Shape> {
    private List<T> shapeList;

    public void processShapes(ShapeProcessor processor){
        for (T shape : shapeList){
            processor.process(shape);
        }
    }
}

および動作 (さまざまな実装を提供するファクトリ クラスを使用することもできます):

public class ShapeProcessor {

    public void process(Shape shape) {

    }

    public void process(ColoredShape shape){

    }
}

または、完全なVisitor Patternに入ります:

public abstract class Shape {
    public void accept(ShapeProcessor processor){
        processor.process(this);
    }
}

public interface ShapeProcessor {
    public void process(Shape shape);
    public void process(ColoredShape shape);
}

public class ShapeManager {
    private List<Shape> shapeList;

    public void processShapes(ShapeProcessor processor){
        for (Shape shape : shapeList){
            shape.accept(processor);
        }
    }
}

これにより、複数の種類のシェイプを列挙し、さまざまな種類の ShapeProcessor からのさまざまな種類のプロセス メソッドを適用できます。マネージャーはそれらのいずれも気にしません。

于 2013-01-16T10:11:17.403 に答える
1

問題は、単一の属性 (リスト形状) を 2 つの場所 (一部は親クラス、一部は子クラス) で構築していることだと思います。これは明らかに良い設計ではありません。変更する必要があります。正確な方法は言えませんが、各コンストラクター内でリストを作成するのではなく、リストをコンストラクターへの引数として (少なくとも親コンストラクターに対しては) 提供することが 1 つの解決策になると思います。そうすれば、ColoredShapeManager などの子クラスを使用しているときに、ColoredShape のリストを作成し、それを子コンストラクター内から親コンストラクターに渡すことができます。そうすれば、すべての子メソッドで ColoredShape のみを扱うことになります。一方、親を使用している場合は、シェイプ (コンストラクターを介して渡される) のみが存在します。

于 2013-01-09T17:27:12.913 に答える
1

デザインは機能する可能性がありますが、実行時に shape s が実際に shape であるかどうか、または命令を使用して ColoredShape であるかどうかを確認する必要がありますinstanceOf(class)。さまざまな種類の図形を追加し始めると、面倒になる可能性があります。それを行う正しい方法は、各形状が実装するインターフェイスを定義することです。このようにして、各形状を同じ方法で使用できます。

複合パターンを使用しないのはなぜですか?

public interface IShape { public int enumerate(); }


public class Shape implements IShape {

int id;

public int enumerate() {
    return id;
}

}

public class ShapeColor extends shape {

    int color;

    public int enumerate() {

        return //whatever you need;
    }

}

import java.util.List;

public class ShapeManager implements IShape {

    List<IShape> shapes;

    public int enumerate() {
        for(IShape s : shapes){
            //do stuff
        }
        return 0;
    }

}

このようにすることで、ColoredShapeManager に追加したい動作を取り、それを直接 ColoredShape に入れます (より論理的に思えます)。

于 2013-01-18T01:05:03.847 に答える