首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >避免了在java继承中强制转换的需要。

避免了在java继承中强制转换的需要。
EN

Stack Overflow用户
提问于 2017-10-01 05:41:05
回答 3查看 93关注 0票数 0

假设我有一个简单的继承结构,如下所示:

代码语言:javascript
复制
class Shape {
   int id;
}

class Circle extends Shape {
   int radius;
}

class Square extends Shape {
   int length;
}

class ToyBox {
   List<Shape> shapes;
}

这些对象不能以任何方式增加(不能添加方法/字段/访问器。以任何方式更改文件),应该被视为不可变的/最终的。我必须将这些shape对象中的每一个都返回到我正在工作的系统的另一个部分,并在每个项目旁边添加一些额外的信息。例如:

代码语言:javascript
复制
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的实例,然后对圆形、正方形等进行强制转换,然后构造每个相应的“扩展”对象。这让我有点不舒服,所以我想知道是否有其他方法来设计这样的系统?

EN

回答 3

Stack Overflow用户

发布于 2017-10-01 05:53:59

如果您需要避免强制转换和使用instanceof运算符,您可能会考虑使用Vistor设计模式。如果将其应用于您的示例,可能如下所示:

代码语言:javascript
复制
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
   }

}
票数 1
EN

Stack Overflow用户

发布于 2017-10-01 06:14:15

我可以提出一种更接近模式匹配的方法。它不能使用继承解决问题,但它应该提供与访问者模式相同的优势,而不是它的重量级方面。

只需引入ShapeType枚举,使每个形状返回其类型并使用switch-case结构来实现您的逻辑。可能更具可读性。

票数 0
EN

Stack Overflow用户

发布于 2017-10-01 07:48:51

看起来你处于一个非常艰难的境地,不能拥有shape类,但是我认为你可以添加shape代理。它添加了一个额外的层,但提供了扩展形状的能力,以及在需要时对界面的额外控制。

假设给定一个Shape,如下所示:

代码语言:javascript
复制
public class Shape {
    public void doSomethingWithShape() {}
}

您可以像这样提供一个ShapeProxy (实现Shape接口并为其提供一个代理):

代码语言:javascript
复制
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);
    }
}

同样,每个附加形状都有代理:

代码语言:javascript
复制
public class CircleProxy extends Circle implements IShapeProxy {

    @Override
    public ExtendedCircle getExtended() {
        return new ExtendedCircle(this);
    }
}

当然,您可以这样使用它:

代码语言:javascript
复制
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的建议结合起来,并添加一个如下所示的类型(对接口的更改未显示):

代码语言:javascript
复制
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;
        ...
        }
    }
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/46507286

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档