假设我有一个简单的继承结构,如下所示:
class Shape {
int id;
}
class Circle extends Shape {
int radius;
}
class Square extends Shape {
int length;
}
class ToyBox {
List<Shape> shapes;
}这些对象不能以任何方式增加(不能添加方法/字段/访问器。以任何方式更改文件),应该被视为不可变的/最终的。我必须将这些shape对象中的每一个都返回到我正在工作的系统的另一个部分,并在每个项目旁边添加一些额外的信息。例如:
class extended Shape {
int id;
}
class ExtendedCircle extends ExtendedShape {
public Circle circle;
public Blah circleStuff;
public ExtendedCircle(Circle circle) {...}
}
class ExtendedSquare extends ExtendedShape {
public Square square;
public Blah squareStuff;
public ExtendedSquare(Square square) {...}
}我能想到的完成这项任务的唯一方法就是遍历shapes列表,做一个ToyBox的实例,然后对圆形、正方形等进行强制转换,然后构造每个相应的“扩展”对象。这让我有点不舒服,所以我想知道是否有其他方法来设计这样的系统?
发布于 2017-10-01 05:53:59
如果您需要避免强制转换和使用instanceof运算符,您可能会考虑使用Vistor设计模式。如果将其应用于您的示例,可能如下所示:
class Shape {
int id;
public void visitingShape(ToyBox box) {
box.visitingShape(this);
}
}
class Circle extends Shape {
int radius;
public void visitingShape(ToyBox box) {
box.visitingCircle(this);
}
}
class Square extends Shape {
int length;
public void visitingShape(ToyBox box) {
box.visitingSquare(this);
}
}
class ToyBox {
List<Shape> shapes;
public visitingShape(Shape shape) {
// Do logic related to the shape
}
public visitingCircle(Circle shape) {
// Do logic related to the circle
}
public visitingSquare(Square shape) {
// Do logic related to the square
}
}发布于 2017-10-01 06:14:15
我可以提出一种更接近模式匹配的方法。它不能使用继承解决问题,但它应该提供与访问者模式相同的优势,而不是它的重量级方面。
只需引入ShapeType枚举,使每个形状返回其类型并使用switch-case结构来实现您的逻辑。可能更具可读性。
发布于 2017-10-01 07:48:51
看起来你处于一个非常艰难的境地,不能拥有shape类,但是我认为你可以添加shape代理。它添加了一个额外的层,但提供了扩展形状的能力,以及在需要时对界面的额外控制。
假设给定一个Shape,如下所示:
public class Shape {
public void doSomethingWithShape() {}
}您可以像这样提供一个ShapeProxy (实现Shape接口并为其提供一个代理):
public class ShapeProxy extends Shape implements IShapeProxy {
// Optional
@Override
public void doSomethingWithShape() {
// Do something extra if needed.
}
// From IShapeProxy
@Override
public ExtendedShape getExtended() {
return new ExtendedShape(this);
}
}同样,每个附加形状都有代理:
public class CircleProxy extends Circle implements IShapeProxy {
@Override
public ExtendedCircle getExtended() {
return new ExtendedCircle(this);
}
}当然,您可以这样使用它:
public static void main(String[] args) {
List<IShapeProxy> shapes = new ArrayList<>();
shapes.add(new ShapeProxy());
shapes.add(new CircleProxy());
shapes.add(new SquareProxy());
List<ExtendedShape> extendedShapes = new ArrayList<>();
shapes.forEach(s -> extendedShapes.add(s.getExtended()));
}我更喜欢这种方式,但是如果你不能改变List的类型,那么你仍然可以把它们作为Shapes放进去,然后强制转换以获得扩展类型。尽管如此,这仍然是一种常见的造型,不需要了解手边的形状类型。
如果这看起来像是太多的,或者如果你想将扩展与代理分开,你可以将代理的想法与Dici的建议结合起来,并添加一个如下所示的类型(对接口的更改未显示):
public enum ShapeType {
SHAPE, CIRCLE, SQUARE
}
public class CircleProxy extends Circle implements IShapeProxy {
// From IShapeProxy
@Override
public ShapeType getType() {
return ShapeType.CIRCLE;
}
}
// And...
for (IShapeProxy proxy : shapes) {
switch (proxy.getType()) {
case SHAPE:
// Build the extended type.
break;
...
}
}
}https://stackoverflow.com/questions/46507286
复制相似问题