简体   繁体   中英

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. 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).

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.

Since Player implements Consumer, the onConsume method in Food should just call the consume() method on the the Consumer. 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.

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. In this case you would need a separate set of classes that know what to do when Food is consumed by a Player.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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