【问题标题】:instanceof versus polymorphisminstanceof 与多态性
【发布时间】:2011-06-10 01:07:36
【问题描述】:

我在使用 instanceof 运算符时遇到问题。我试图避免它。基本上,我有以下结构:

class Shape {}
class Triangle extends Shape {}
class Rectangle extends Shape {}

ShapeParser s;
while (s.hasNext())
     parseShape(s.next()); // returns a Shape object

void parseShape(Triangle t) { // do stuff } // KEY POINT HERE
void parseShape(Rectangle t) { // etc }

我要说的关键点是:我想做一个函数的参数重载,但它没有按我的预期工作(编译错误)。我试图避免:

void parseShape(Shape s)
{
     if (s instanceof Triangle) ...
}

更新:似乎共识是创建一个基类方法: parseShape() 来做 起重。我想澄清我的问题:这个问题的动机与观察者模式有关。假设我有以下 Observer 对象的有效载荷方法:

    public void update(Observable obj, Shape objectPayload){} 
// note: the objectPayload is usually of type Object

而不是执行:

public void update(Observable obj, Shape objectPayload)
{
       if (objectPayload instanceof Triangle)
          // do stuff
       else if (objectPayload instanceof Rectangle)
          // etc
}

我想做:

public void update(Observable obj, Shape objectPayload)
{
       parseShape(objectPayload);
}

    void parseShape(Triangle t) {  } // do stuff
    void parseShape(Rectangle t) { }

【问题讨论】:

  • 请发布错误...
  • 为什么你的矩形叫t? :-)
  • 更新问题;请看。
  • 不,不,一百次不!不要让我过来打你 :-) 在 OO 中,object/class 是上帝。如果您发现自己处于 code 再次成为主要事物的情况,那么您将回到 OO 之前的日子。甚至观察者模式也应该遵循以下规则:...自动通知他们任何状态变化,通常通过调用他们的方法之一。
  • 看起来越来越像你想要的访问者模式。例如,参见this thread。将其放入您的 Shape 层次结构中,您就无需使用解析代码或您想要类似应用的任何其他操作的代码来污染该层次结构。

标签: java polymorphism


【解决方案1】:

您可以将parseShape 移动到每个 Shape 类中。或者,您可以使用访客模式。 this thread 的解决方案中显示了一个巧妙的反射技巧,可以避免 Java 中完整访问者模式的复杂性。

更新:

以下是访问者模式的秘诀:

  1. 声明一个接口:

    公共接口 ShapeVisitor { 访问(三角形); 访问(矩形); // ... }
  2. Shape中,声明一个抽象方法acceptVisitor

    类形状{ 公共抽象无效acceptVisitor(ShapeVisitor访问者); }
  3. 在每个具体类中,实现acceptVisitor

    类三角形扩展形状{ 公共无效acceptVisitor(ShapeVisitor访问者){ 访客.visit(this); } }
  4. 声明您的 ParseVisitor 类以实现 ShapeVisitor 并实现所有必需的方法(只需将每个 parseShape 方法重命名为 visit)。

这样做的好处是,首先,它将解析代码排除在 Shape 层次结构之外,并将其集中在一个单独的解析类中;其次,如果您稍后决定需要执行一些其他操作(例如渲染),您可以应用相同的模式无需更改任何 Shape 类。这种方法的最大缺点是,如果您决定添加另一个 Shape 子类,则必须更改所有实现 ShapeVisitor 的类。

【讨论】:

  • 谢谢,这正是我要找的。​​span>
【解决方案2】:

如果您的parseShape() 方法在Shape 中声明,则它可以在TriangleRectangle 中被覆盖。

即:

ShapeParser s;
while (s.hasNext())
     // Calls the proper implementation of parseShape()
     s.next().parseShape();

【讨论】:

  • +1。这是正确的OO方式。在您的代码审查中使用instanceof 通常应该是一种冒犯:-)
  • 你把世界翻了个底朝天,然后它就位了。 +1 焦油和羽毛。
【解决方案3】:

嗯,在基类中添加一个 parse 方法,然后循环并遍历形状列表并调用 s.parse()?

【讨论】:

    【解决方案4】:

    我认为错误是因为 s.next() 返回 Shape。合乎逻辑的事情是 将 parse() 方法添加到 shape 并调用 s.parse()

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-10
      • 2011-06-26
      • 1970-01-01
      • 2011-01-10
      • 2018-08-14
      相关资源
      最近更新 更多