【问题标题】:Alternative to instanceof?替代实例?
【发布时间】:2011-04-19 19:31:10
【问题描述】:

我听说使用我可以同意的 instanceof 或等效项(http://www.javapractices.com/topic/TopicAction.do?Id=31When should and shouldn't instanceof be used?)是糟糕的设计,主要是因为它会使代码难以重用。

但是,在某些情况下,我发现很难想出一个好的替代 instanceof 的方法。例如,假设我想制作一款实时策略游戏。游戏由障碍物、建筑物和坦克组成,所有这些都放置在一个网格上,每个实体恰好占据网格中的一个单元。所以我创建了实体类,它是障碍、建筑和坦克类的超类。网格由实体的实例组成。在每次更新期间,我希望每辆坦克都能瞄准射程内的敌方坦克并射击。因此,一个简单的方法是让每个坦克向网格询问坦克范围内的所有实体,然后遍历所有这些实体并检查它们是否是 Tank 类的实例。

作为使用 instanceof 的替代方法,我唯一的尝试是使用设计模式 Visitor。访问者被实体(entity->acceptVisitor(visitor)) 接受,该实体又调用visitor->visitObstacle(this)visitor->visitBuildig(this)visitor->visitTank(this) 方法之一。 然而,这迫使我创建了大量的访问者,对于我想在实体上进行的每一项任务几乎都有一个新的访问者。另一个问题是,在许多情况下,访问者在实体上调用相同的方法,无论它是从哪个类构造的。例如,当一个实体想要检查另一个实体是否静止时,可能会发生这种情况:

#Python代码:

class StationaryEntityGatherVisitor:
    def __init__(self):
        self.stationaryEntities = []
    
    def visitObstacle(self, obstacle):
        self._addIfStationary( obstacle )
    
    def visitBuildig(self, building):
        self._addIfStationary( building )
            
    def visitTank(self, tank):
        self._addIfStationary( tank )
            
    def _addIfStationary(self, entity):
        if entity.isStationary():
            self.stationaryEntities.append( entity )
    
    def getStationaryEntities():
        return self.stationaryEntities

当然,在这种情况下,我可以让实体直接询问另一个实体是否静止,而不是让访问者这样做。但在那种情况下,我在检查实体的属性时会不一致。让向实体询问某些属性的方法(直接或通过访问者)根据我是否需要检查实体类型而有所不同,在我看来,这似乎是一个非常奇怪的设计。

那么,在上述问题中,除了使用 instanceof 之外,您还有其他选择吗?

【问题讨论】:

    标签: design-patterns instanceof


    【解决方案1】:

    暂时忘记您的访客解决方案,只专注于您的需求:

    网格由实体的实例组成。在每次更新期间,我希望每辆坦克都能瞄准射程内的敌方坦克并射击。因此,一个简单的方法是让每个坦克向网格询问坦克范围内的所有实体,然后遍历所有这些实体并检查它们是否是 Tank 类的实例。

    为什么不直接过滤列表?

    targetablesInRange = filter(isTargetable, grid.itemsInRangeOf(self))
    

    而不仅仅是坦克,您应该询问使它们成为目标的实体的属性。这可能会在基类中返回 false 并被 Tank 和您稍后介绍的其他应触发的类覆盖。

    【讨论】:

      【解决方案2】:

      那么,您是否考虑过遍历所有坦克以查看它们是否在射程内,而不是遍历射程内的所有实体以查看它们是否是坦克?似乎它会在迭代和 instanceof 调用上为您节省大量时间...

      【讨论】:

        【解决方案3】:

        一般来说,多态是避免不必要的 instanceof 运算符的方法。

        【讨论】:

          【解决方案4】:

          我不知道您是否需要使用访问者来处理这种行为。通过使用一般多态性,您的案例可以很容易地完成。我最初打算建议一个工厂方法和类型变量,但解决方案可能更简单。

          所以你有一个通用的抽象超类。 (实体)。所以在这个类中,您可以定义一个名为 hitByMissile() (或其他)的方法。在您的坦克类中,您可以制作 hitByMissile,其性能与障碍物不同。您的代码不应决定每个实体的行为方式。行为应该由对象本身定义。因此,您可以迭代实体并调用该方法。

          【讨论】:

          • 我有这样一个习惯,即在我所有的答案开始时都带有免责声明,我可能不明白这个问题:)。这是为了逃避一般的势利,但如果解决方案不适合你,请评论我。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-12-13
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多