替代instanceof?

发布于 2024-11-02 11:43:10 字数 1839 浏览 3 评论 0原文

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

然而,在某些情况下,我发现很难想出一个很好的替代方法来替代instanceof。例如,假设我想制作一款即时策略游戏。游戏由障碍物、建筑物和坦克组成,全部放置在网格上,每个实体恰好占据网格中的一个单位。因此,我创建了 Entity 类,它是 Obstacle、Building 和 Tank 类的超类。网格由实体的实例组成。在每次更新期间,我希望每辆坦克都能瞄准并射击射程内的敌方坦克。因此,一个简单的方法是让每个坦克向网格询问坦克范围内的所有实体,然后迭代所有这些实体并检查它们是否是 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之外,还有其他替代方法吗?

I've heard that it is bad design to use instanceof or equivalent (http://www.javapractices.com/topic/TopicAction.do?Id=31, When should and shouldn't instanceof be used?) which I can agree on, mainly because it can make the code hard to reuse.

However, in some cases I've found it hard to come up with a good alternative to instanceof. For example, say that I want to make a Real-Time-Strategy game. The game consists of obstacles, buildings and tanks, all placed on a grid and each entitity takes up exactly one unit in the grid. So I create the class Entity which is the superclass of the classes Obstacle, Building and Tank. The grid consists of instances of Entity. During each update I want each tank to aim and shoot on an enemy tank within range. So, an easy way to do this would be for each tank to ask the grid for all entities within the tanks range and then iterate over all these entities and check if they are an instance of the class Tank.

My only attempt as an alternative of using instanceof was to use the design pattern Visitor. The visitor gets accepted by an entity (entity->acceptVisitor(visitor)) which in turn calls one of the methods visitor->visitObstacle(this), visitor->visitBuildig(this) or visitor->visitTank(this).
This, however, forced me to create a lot of visitors, almost one new for every single task that I wanted to make on entities. Another problem is that in many cases the visitor calls the same method on the entity, no matter what class it is constructed from. This could for example happen when an entity wants to check if another entity is stationary or not:

#Python code:

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

I could, of course, let the entity in this case just ask another entity if it is stationary directly instead of letting a visitor do that. But in that case I would not be consistent on checking properties of entities. To let the method of asking entities about some property (directly or through a visitor) vary, depending on if I need to check the entities type or not, would, in my opinion, seem like a pretty odd design.

So, do you have any other alternative to using instanceof in the problem described above?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

年华零落成诗 2024-11-09 11:43:10

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

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

为什么不直接过滤列表呢?

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

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

Forgetting about your Visitor solution for a second, and concentrating on just your requirement:

The grid consists of instances of Entity. During each update I want each tank to aim and shoot on an enemy tank within range. So, an easy way to do this would be for each tank to ask the grid for all entities within the tanks range and then iterate over all these entities and check if they are an instance of the class Tank.

Why not just filter the list directly?

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

Instead of just Tanks, you should be asking about a property of entities that makes them a target. This could return false in the base class and be overridden by Tank and other classes that you introduce later that should be fired upon.

拥醉 2024-11-09 11:43:10

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

Well, have you considered iterating over all of the tanks to see if they're in range instead of all of the entities in range to see if they're tanks? Seems like it would save you a lot of time on both iteration and instanceof calls...

長街聽風 2024-11-09 11:43:10

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

In general, polymorphism is the way to avoid unnecessary instanceof operator.

苯莒 2024-11-09 11:43:10

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

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

I do not know if you need to use Visitor to handle this behavior. Your case could be very easily accomplished by using general polymorphism. I was initially about to suggest a factory method and type variable, but the solution could be even simpler.

So you have a general Abstract Superclass. (Entity). So in this class you can define a method called hitByMissile() (or whatever). In your tank class, you can make hitByMissile, perform differently from lets say an Obstacle. Your code should not decide on how each entity behave. The behavior should be defined by the object itself. So you can just iterate over the entities and call the method.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文