我有一个基类ShapeManager
,其中包含我想要的形状列表
enumerate()
。然后有一个想要的专业化ColoredShapeManager
处理专门的ColoredShape
而不是Shape
s:
+----------------+ +-------------------------------------+
| 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()
想要的有缺陷的
过程ColoredShape
。因此它会抛出元素,但还有一些元素
(由基类添加的那些)属于Shape
类型,并且强制转换将失败。
那是:
shapes
。enumerate()
应该可以访问ColoredShape
。我是否应该拆分列表并在两个管理器中创建私人列表?然后在子项中枚举只会迭代“它”类型的形状,并在开始/结束时调用父项enumerate()
。
答案 0 :(得分:6)
您可以将形状类型添加为经理类的“类型参数”。基本上,ColoredShapeManager
可以扩展ShapeManager<ColoredShape>
,此T
将是您的内部List
数据结构的类型。另外,如果您的ColoredShapeManager
没有对ColoredShapes
做任何具体的事情,我会认为它甚至不需要新课程。但是,这又取决于你构建app / design的方式。
答案 1 :(得分:3)
访客模式会适合你吗?
形状
public void doSomething(ShapeManager) {
...
}
ShapeManager
abstract void enumerate() {
for (Shape shape: shapes) {
shape.doSomething(this);
}
}
然后你不需要知道类型,每个形状派生可以有自己的实现。
答案 2 :(得分:2)
为什么不分离行为和 generify 容器?
容器:
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);
}
}
}
这允许枚举多种形状并应用不同类型的处理方法,这些形状也来自不同类型的ShapeProcessors。经理不关心他们中的任何一个。
答案 3 :(得分: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,因为存在类型限制。
答案 4 :(得分:1)
我认为问题在于您在两个地方构建单个属性 - 列表形状:部分位于父级,部分位于子级。这显然不是一个好的设计。你需要改变它。虽然我不能确切地说明如何,但我认为一个解决方案可能是你提供列表作为构造函数的参数(至少对于父构造函数),而不是在每个构造函数中创建它们。这样,当您使用诸如ColoredShapeManager之类的子类时,您可以构造ColoredShapes列表,并从子构造函数中将其传递给父构造函数。这样,在你所有的孩子方法中,你只会处理ColoredShape。而如果您使用父级,则只有Shapes(通过构造函数传递)。
答案 5 :(得分:1)
您的设计可以正常工作,但您必须在运行时检查形状s是否确实是形状,或者是否是使用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中(这似乎更合乎逻辑)