2013-01-09 8 views
5

私は enumerate()の形のリストを持つ基本クラスShapeManagerを持っています。その後Shape秒のColoredShapeの代わりに、特殊な処理に を望んでいる専門ColoredShapeManagerがあります:子どもと基底型のリストを共有する

+----------------+  +-------------------------------------+ 
| 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がColoredShapeManager.enumerate()が プロセスColoredShape秒に望んでいるので、これは欠陥があるようで、その 子供とshapes: List<Shape>を共有する必要があるかどうかわかりませんよ。したがって、要素をキャストしますが、 (基本クラスによって追加された要素)の一部はShapeであり、キャストは失敗します。

ある:形状の

  • 両方のタイプがリストshapesで終わります。
  • enumerate()には、ColoredShapeへのアクセス権が必要です。

リストを分割して、2人の管理者のそれぞれでプライベートリストを作成してください。次に、子の中で列挙すると、 "その"型の形を反復し、親のenumerate()を開始点/終了点として呼び出します。

+0

http://www.asciiflow.com/#Draw素晴らしいツール! –

+0

最適な解決策は、シェイプで何をしているかによって異なります。例えば、あなたが 'enumerate'のループの形を描画しようとしている場合(私の意見では、表示するコードの名前の選択肢が貧弱です)、描画する場合、すべての図形が色付きで、そうではありません。すべてのインスタンスに適用される 'Shape'クラスの呼び出しメソッドが混在し、 'Shored'インスタンスには適用されない 'ColoredShape'クラスのメソッドを呼び出すと、その組み合わせによって最適な方法が判断されることがあります。 –

+0

問題のポイントは、 'ColoredShape'固有の関数/プロパティ(この例では' color')を使う方法です。 –

答えて

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); 
     } 
    } 
} 

これにより、複数の種類の図形が列挙され、異なる種類のpr異なる種類のShapeProcessorsからも適用されます。マネージャーはそれらのいずれかを気にしません。

+0

基本的に私が昨日言ったこと) – TedTrippin

+0

私が見る唯一の欠点は、ShapeProcessorを定義するために将来のすべての* Shapeクラスを予見しなければならないことです。 –

+0

@MichaWiedenmann正確には、すべての種類の 'process()'メソッドを同じクラスに置く必要はありません。1.適切なプロセッサを返すために 'ProcessorProvider'(ファクトリ)を渡すことができます。 2.新しいShapeクラスごとにvisitorパターンで示されるように、単にShapeProcessorインタフェースを実装するコンパニオンクラスを構築するだけです。 –

1

私は、あなたが1つの属性(リストシェイプ)を2つの場所に作成していると思います。部分的には親に、部分的に子クラスにあります。これは明らかに良いデザインではありません。あなたはそれを変更する必要があります。私はちょうど方法を言うことはできませんが、各コンストラクタ内に作成するのではなく、コンストラクタ(少なくとも親コンストラクタの場合)の引数としてリストを提供できるということが考えられます。これにより、ColoredShapeManagerなどの子クラスを使用しているときに、ColoredShapesのリストを作成し、子コンストラクタ内から親コンストラクタに渡すことができます。そうすれば、あなたの子供のすべての方法で、ColoredShapeだけを扱うことになります。一方、親を使用している場合は、シェイプ(コンストラクターを通過)のみが存在します。

+0

Baseは他のメンバー関数にも要素を追加できるということをより明確に述べたはずです。それらは子供にキャストすることはできません。 –

6

マネージャタイプの「タイプパラメータ」としてシェイプタイプを追加できます。したがって、基本的にColoredShapeManagerShapeManager<ColoredShape>に拡張でき、このTは内部のListデータ構造のタイプになります。また、ColoredShapeManagerColoredShapesに固有のことをしていない場合、私はそれが新しいクラスを必要としないと主張します。しかし、もう一度それはあなたのアプリ/デザインを構成する方法に依存します。

+0

ありがとう、私はより明確にするために私の質問を更新しました。 'ShapeManager'をBaseクラスとして使いたいです。後で 'ColoredShapeManager'から継承しても(この子は最初の子ではなくベースを拡張するので)、あなたが提案したように私はできないと思います。私はまた、型パラメータが実装の詳細であり、 'ShapeManager'の型の一部としてパブリッシュされるべきではないと考えています。インターフェイスの代わりにクラスを使用しているのは私の間違いです。 –

+0

私はあなたの要点を見ていますが、型パラメータを公開することはカプセル化に違反してはいけません。結局のところ、あなたはクラス名でそれを公開しています。シェイプのみを使用するようにクラスを制限するには、パラメータ ' 'を使用することができます。これは実際にあなたが実際にシェイプを処理していることを確実にするために推奨されます。 – MathSquared

3

訪問者のパターンはここに適していますか?

形状

public void doSomething(ShapeManager) { 
    ... 
} 

ShapeManager

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

次にあなたがタイプを知る必要がありwouldntの各形状誘導体は、独自の実装を持つことができます。

+0

私は彼の答えがわかりやすいのでSingularityを授与しましたが、あなたと私を助けてくれたすべての人にはまだ感謝しています。私はこれがあなたとうまくいくことを望みます。 –

1

あなたのデザインはうまくいくかもしれませんが、実行時に形が本当に形かどうか、またはinstanceOf(class)命令を使ってColoredShapeかどうかをチェックする必要があります。さまざまな種類の図形を追加すると、面倒な作業が発生する可能性があります。これを行う正しい方法は、それぞれのシェイプが同じ方法で使用できるように、シェイプが実装するインターフェイスを定義することです。

composite pattern ?

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に入れたかった行動を取るようにすることで

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   | 
|    |  |  }        | 
|    |  | }         | 
+----------------+  +-------------------------------------+ 

をこのように、欠点は、型制約があるので、あなたがリストに任意の形状を追加することはできませんです。

関連する問題