避免在 Java 中实例

2022-09-03 02:27:39

在大学的某个阶段(随后在十几岁的地方读过),我被告知使用应该只作为“最后的手段”。考虑到这一点,任何人都可以判断我拥有的以下代码是否是最后的手段。我四处查看了堆栈溢出,但找不到类似的情况 - 也许我错过了它?instanceof

private void allocateUITweenManager() {
   for(GameObject go:mGameObjects){
      if (go instanceof GameGroup) ((GameGroup) go).setUITweenManager(mUITweenManager);
   }
}

哪里

  • mGameObjects是一个数组,其中只有一部分是类型GameGroup
  • GameGroup是抽象类 的子类。GameObject
  • GameGroup使用具有方法的接口UITweenablesetUITweenManager()
  • GameObject不使用接口UITweenable

我想我可以同样(并且可能应该)在上面的代码中替换 - 我会问同样的问题。GameGroupUITweenable

有没有另一种方法可以避免?因此,这段代码不会失败(我认为,对吧?),但是鉴于负面新闻似乎得到了,我是否在我在这里使用的某个地方犯了OOP的一些主要罪行?instanceofinstanceofinstanceof

提前致谢!


答案 1

我在大学的编译器课上学到了,我认为它可能适用于你的场景。请考虑以下代码:Visitor pattern

public class GameObjectVisitor {

    public boolean visit(GameObject1 obj1) { return true; }
    .
    .
    // one method for each game object
    public boolean visit(GameGroup obj1) { return true; }
}

然后你可以在接口中放一个方法,如下所示:GameObject

public interface GameObject {

    .
    .
    public boolean visit(GameObjectVisitor visitor);
}

然后每个实现这个方法:GameObject

public class GameGroup implements GameObject {

    .
    .
    .
    public boolean visit(GameObjectVisitor visitor) {
        visitor.visit(this);
    }
}

当您具有 复杂的继承层次结构时,这特别有用。对于您的情况,您的方法将如下所示:GameObject

private void allocateUITweenManager() {

    GameObjectVisitor gameGroupVisitor = new GameObjectVisitor() {
        public boolean visit(GameGroup obj1) {
            obj1.setUITweenManager(mUITweenManager);
        }
    };

    for(GameObject go:mGameObjects){
      go.visit(gameGroupVisitor);
   }
}

答案 2

编辑

您可以在此处执行两项主要操作,以减轻此特定实例的负担。(双关语?instanceof

  1. 按照我最初的答案建议,将你针对的方法移动到你正在迭代的类。在这种情况下,这并不理想,因为该方法对父对象没有意义,并且会像Ted所说的那样造成污染。

  2. 将要迭代的对象的范围缩小到仅熟悉目标方法的对象。我认为这是更理想的方法,但在当前形式的代码中可能行不通。

就我个人而言,我避免像瘟疫一样,因为它让我觉得我完全错过了一些东西,但有时这是必要的。如果你的代码以这种方式布局,并且你无法缩小要迭代的对象的范围,那么可能会很好地工作。但这看起来是一个很好的机会,可以看看多态性如何让你的代码在未来更容易阅读和维护。instanceofinstanceof

我在下面留下原始答案,以保持评论的完整性。

/编辑

就个人而言,我不认为这是使用.在我看来,你可以利用一些多态性来实现你的目标。instanceof

你有没有考虑过做一个方法?这样做有意义吗?setUITweenManager(...)GameObject

如果它确实有意义,则可以让默认实现不执行任何操作,并重写该方法以执行您希望它执行的操作。此时,您的代码可能如下所示:GameGroup

private void allocateUITweenManager() {
   for(GameObject go:mGameObjects){
       go.setUITweenManager(mUITweenManager);
   }
}

这是操作中的多态性,但我不确定这是否是您当前情况的最佳方法。如果可能的话,迭代对象会更有意义。CollectionUITweenable