简体   繁体   English

避免使用OOP的instanceof

[英]Avoiding instanceof with OOP

class Entity {
    // various fields and methods
}

class MobileEntity extends Entity {
    // various fields and methods
}

interface Consumer {
    public void consume(final Consumable c);
}

interface Consumable {
    public void onConsume(final Consumer c);
}

class Player extends MobileEntity implements Consumer {
    // Override methods, etc
    // Can consume
}

class Npc extends MobileEntity {
    // Cannot consume anything
}

class Food implements Consumable {
    public void onConsume(final Consumer c) {
        if (c instanceof Player) {
            healPlayer();
            removeFood(1);
        }
    }
}

Sorry for putting all of the code first, but I figured it'd be easier for me to explain, and for you to understand if you saw it. 抱歉,所有代码都放在首位,但是我认为这对我来说更容易解释,并且让您理解是否看到了它。 This is for a game I'm developing. 这是我正在开发的游戏。 The problem I'm having is how to deal with a Consumable (be it Food or Drink) without using the instanceof operator. 我遇到的问题是如何在不使用instanceof运算符的情况下处理消耗品(无论是食物还是饮料)。 I would like to avoid setting the concrete class Player in the Food class (because there could end up being hundreds of different types of Food), but there are exceptions to the contract in each case (which indicates a problem). 我想避免在Food类中设置具体的Player类(因为最终可能有成百上千种不同类型的Food),但是每种情况下合同都有例外(表明存在问题)。

Not all Entity implementations will have a health field. 并非所有的实体实现都会有一个健康字段。 They might, but if so, I would need to mark certain ones as "attackable", and then have a test 他们可能会,但是如果是这样,我将需要将某些标记为“可攻击”,然后进行测试

void applyDamage(int damage) {
    if (attackable) {
        health -= damage;
    }
}

Which introduces new problems, due to hard-coding behaviour (an indicator to introduce a new class) 由于硬编码行为而引入了新问题(引入新类的指示符)

I've heard of possibly using the Visitor pattern in similar thread, but I don't think it applies in the current situation. 我听说可能在类似的线程中使用Visitor模式,但我认为它不适用于当前情况。

Since Player implements Consumer, the onConsume method in Food should just call the consume() method on the the Consumer. 由于播放器实现了消费者,食品中onConsume方法应该只是调用消耗的消费者()方法。 In this case, the Player's version of consume would do the right job. 在这种情况下,播放器的消费版本将做正确的工作。 instanceof is not only bad but would fail when the objects are decorated. instanceof不仅不好,而且装饰对象时也会失败。

Your Consumer has a consume() method and Player is a Consumer so why not pass the Consumable to the Consumer? 您的消费者有一个消耗()方法,而播放器是消费者,那么为什么不将消耗品传递给消费者呢? On the other hand, it seems like Player, Npc, and Food are all data models so you might want to keep any business logic (such as increasing health or removing food) out of all your models. 另一方面,似乎Player,Npc和Food都是数据模型,因此您可能希望在所有模型中保留任何业务逻辑(例如,增加健康状况或移除食物)。 In this case you would need a separate set of classes that know what to do when Food is consumed by a Player. 在这种情况下,您将需要单独的一组类,这些类知道玩家消耗食物时的处理方式。

要么您有逻辑上的倒退-消耗品应该传递给使用者,消耗品应该具有使用者可以调用的方法,或者所有使用者都应实现消耗品可以调用它们的所有可能方法,并做正确的事情,可能什么都不是。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM