2

我正在编写一个应用程序,它有几个代表世界中事物的类。

世界由一个对象数组表示(世界中存在的所有对象类都继承自该类 - 让我们称之为事物)。

class World {
  Thing[] myObjects;
}

class Thing {}
class AAA extends Thing {}
class BBB extends Thing {}

在某些时候,我需要知道给定位置的对象是否属于给定类型。

我有一些解决方案,并想与熟悉 Java 对象模型的人讨论每种解决方案的优点,因为我习惯了与 Java (CLOS) 不同的对象模型。

解决方案#1

在 World 类中定义方法 isAThinAAA(obj) 和 isAThinBBB(obj)。

这些方法会调用 obj.getClass() 并检查返回的类型是 AAA 还是 BBB。

我看到的问题是必须使用“getClass”来实现它。还是有另一种方法来实现它?

解决方案#2

在Thing类中定义方法isAnAAA()和isAnBBB(),实现返回false。在各自的类(AAA.isAnAAA 和 BBB.isAnBBB)中重新定义它们以返回 true。

这看起来很奇怪,因为最抽象的类会知道其子类的存在。

其他建议?

提前致谢。

4

5 回答 5

4

不如在 Thing 类中写一个抽象方法,然后让AAA'instances 和BBB'instances 重新定义它。您似乎想编写isAnXXX方法,也许您可​​以解释原因。

看,使用instance of运算符和isAnXXX方法不会导致多态性。这不是一件好事。你想要多态性,你需要它……咕噜,咕噜。另外,考虑一下明天你想在CCC你的World. 你的设计应该保证World类不会被触及,就像在打开/关闭原则中一样

所以,总而言之,你可以这样做:

在课堂上:

public abstract class Thing{
   abstract void doSomething();
}

然后在子类中覆盖它

public class AAA extends Thing{

@override
public void doSomething(){ /*do something in AAAs way*/}

}

public class BBB extends Thing{

@override
public void doSomething(){ /*do something in BBBs way*/}

}

然后你可以填写你的Thing[]并做到这一点

   for (Thing t:myOBjects){
       t.doSomething()

   }

每个实例都Thing知道如何doSomething,而无需询问其类型。

于 2011-07-23T16:51:29.957 回答
3

另一种选择是根本没有这些方法。这些方法通常用于决定要做什么。就像是

if(thing is a AAA) {
   ((AAA) thing).method();
} else if (thing is a BBB) {
   ((BBB) thing).method();
}

相反,最好让每个事物知道在需要采取行动时要做什么。你只需要打电话给

thing.method(); // each type know what to do.
于 2011-07-23T16:53:02.660 回答
1

您应该使用instanceof运算符

AAA aaa = new AAA();
if(aaa instanceof AAA) {
    //do something different
}

编辑:汤姆的回答也应该足以解决您的问题,这是一种很好的做法。

于 2011-07-23T16:55:17.673 回答
0

最简单的方法是使用 Java 的内置 instanceof 运算符。例如:

public boolean isAAA(Thing myThing)
{
  return myThing instanceof AAA;
}

然而,许多人会告诉你,使用 instanceof 是糟糕的类设计的症状,而使用不同子类实现不同行为的正确方法是通过多态性。这里的问题是,在 Java 中很容易让一个类根据它是什么派生类型来做不同的事情,但是让一些其他对象根据它所具有的派生类型来不同地对待事物有点棘手。上。这就是双重调度问题。

如果在处理您的 Thing 对象时,您可以将问题分派给其他一些方法,这些方法将根据 Thing 的子类对它做不同的事情,那将是理想的,如下所示:

public void handleThing(Thing myThing)
{
  reactToThing(myThing);
}

public void reactToThing(AAA myThing)
{
  // Do stuff specific for AAA
}

public void reactToThing(BBB myThing)
{
  // Do stuff specific for BBB
}


public void reactToThing(Thing myThing)
{
  // Do stuff for generic Thing
}

然而,在仅支持单次调度的 Java 中,无论 handleThing() 中 myThing 的实际类型如何,reactToThing(Thing) 总是会被调用,并且您永远不会得到您的独特行为。

要解决这个问题,您需要做的是使用访问者模式。这只涉及在您的 Thing 类及其所有子类中添加一些额外的代码,以便为您的 reactToThing() 方法提供一些额外的上下文。因此,假设上述方法都在一个名为 Visitor 的类中。我们可以通过首先将问题交给 Thing 对象本身来重写上述内容,然后多态性将为我们提供适当的上下文(Thing、AAA 或 BBB),以便对象返回给访问者。

所以,我们可以将上面的例子改写如下:

public class Visitor
{
  // ...

  public void handleThing(Thing myThing)
  {
    myThing.accept(this);
  }

  public void reactToThing(AAA myThing)
  {
    // Do stuff specific for AAA
  }

  public void reactToThing(BBB myThing)
  {
    // Do stuff specific for BBB
  }


  public void reactToThing(Thing myThing)
  {
    // Do stuff for generic Thing
  }
}


public class Thing
{
  // ...

  public void accept(Visitor visitor)
  {
    visitor.reactToThing(this);
  }
}


public class AAA
{
  // ...

  public void accept(Visitor visitor)
  {
    visitor.reactToThing(this);
  }
}


public class BBB
{
  // ...

  public void accept(Visitor visitor)
  {
    visitor.reactToThing(this);
  }
}

那么为什么我需要在两个子类中重写相同的 accept() 方法呢?因为否则在调用visitor.reactToThing(this) 方法时,对象仍将处于Thing 上下文中,因此我们会遇到与以前相同的问题。通过在所有三个地方重新实现它,派生类将覆盖父类的实现,并在访问者中调用正确的方法。

当您只想知道正在使用的派生类时,这似乎需要做很多工作,但回报是可扩展性和维护性。现在您不需要到处添加 if (something instanceof somethingElse) 了。具体来说,如果您决定以后需要更改某些内容,例如扩展访问者,您需要维护的重复代码就会减少。

希望能解决你的问题。

于 2011-07-23T17:16:09.213 回答
0

您可以使用 instanceof 或 isInstance http://download.oracle.com/javase/6/docs/api/java/lang/Class.html#isInstance%28java.lang.Object%29

class World {
    Thing[] myObjects;
}
class Thing {}
class AAA extends Thing {}
class BBB extends Thing {}
public class Main {
    public static void main(String[] args) {
        Thing[] things={new AAA(),new BBB()};
        for(Thing thing:things)
            if(thing instanceof AAA)
                System.out.println("i am an AAA");
            else if(thing instanceof BBB)
                    System.out.println("i am a BBB");
        }
}
于 2011-07-23T17:06:18.360 回答