5

我有一个基类ShapeManager,其中包含我想要的形状列表 enumerate()。然后有一个专门ColoredShapeManager化想要处理专门ColoredShape的 s 而不是Shapes:

+----------------+      +-------------------------------------+
| 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()想要处理ColoredShapes。因此它会转换元素,但某些元素(由基类添加的元素)是类型Shape的并且转换会失败。

那是:

  • 两种形状都在列表中shapes
  • enumerate()在子管理器中应该可以访问ColoredShape.

我是否应该拆分列表并在两个经理中的每一个中创建私人列表?然后在孩子中枚举只会迭代“它的”类型的形状并enumerate()在开始/结束时调用父母的形状。

4

6 回答 6

6

您可以将形状类型添加为管理器类的“类型参数”。所以基本上,ColoredShapeManager可以扩展ShapeManager<ColoredShape>,这T将是您内部List数据结构的类型。另外,如果您ColoredShapeManager对 没有做任何具体的事情ColoredShapes,我会争辩说它甚至不需要一个新课程。但话又说回来,这取决于您构建应用程序/设计的方式。

于 2013-01-10T09:49:13.650 回答
3

访客模式在这里适合您吗?

形状

public void doSomething(ShapeManager) {
    ...
}

形状管理器

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

然后你就不需要知道类型,每个形状导数都可以有自己的实现。

于 2013-01-15T11:23:14.210 回答
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){

    }
}

或者,进入完整的访客模式

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

这样,缺点是您不能将任何形状添加到列表中,因为存在类型限制。

于 2013-01-18T10:01:54.983 回答
1

我认为问题在于您正在两个地方构造一个属性 - 列表形状:部分在父类中,部分在子类中。这显然不是一个好的设计。你需要改变它。虽然我不能确切地说出如何,但我认为一种解决方案是您将列表作为参数提供给构造函数(至少对于父构造函数),而不是在每个构造函数中创建它们。这样,当您使用 ColoredShapeManager 等子类时,您可以构造 ColoredShape 列表,并将其从子构造函数中传递给父构造函数。这样,在您的所有子方法中,您将只处理 ColoredShape。同时,如果您使用父级,则只有 Shapes(通过构造函数传递)。

于 2013-01-09T17:27:12.913 回答
1

您的设计可以工作,但您必须在运行时检查形状 s 是否确实是一个形状,或者它是否是使用instanceOf(class)指令的 ColoredShape。如果您开始添加许多不同类型的形状,这样做会变得混乱。正确的做法是定义每个形状将实现的接口,这样每个形状都可以以相同的方式使用。

为什么不使用复合模式?

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 回答