2

我听说使用 instanceof 或等效项(http://www.javapractices.com/topic/TopicAction.do?Id=31什么时候应该和不应该使用 instanceof ?)是不好的设计,我可以同意on,主要是因为它会使代码难以重用。

然而,在某些情况下,我发现很难找到一个好的替代 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 之外,您还有其他选择吗?

4

4 回答 4

1

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

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

为什么不直接过滤列表?

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

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

于 2011-04-19T19:44:08.003 回答
0

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

于 2011-04-19T19:37:07.053 回答
0

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

于 2011-04-19T19:39:39.767 回答
0

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

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

于 2011-04-19T19:42:05.567 回答