如何避免在 Java 中实例

2022-09-02 00:31:31

在我的应用程序中,我有一个2d实体数组来表示网格。网格中的每个位置都可以是空的,也可以被实体占用(在本例中,它只是一个人或一堵墙)。现在,我用来检查一个实体是人还是一堵墙。instanceof

我正在考虑为每个实体提供一个方法,该方法返回一个声明其类型的方法,即墙实体将返回。我想知道这是否是删除使用的最佳主意,或者在这种情况下是否合适?enumEntityType.WALLinstanceofinstanceof


答案 1

使用“告诉,不要问”:与其问对象它们是什么,然后对此做出反应,不如告诉对象该做什么,然后墙壁或人们决定他们如何做他们需要做的事情。

例如:

而不是像这样的东西:

public class Wall {
    // ...
}

public class Person {
    // ...
}

// later
public class moveTo(Position pos) {
    Object whatIsThere = pos.whatIsThere();
    if (whatIsThere instanceof Wall) {
         System.err.println("You cannot move into a wall");
    }
    else if (whatIsThere instanceof Person) {
         System.err.println("You bump into " + person.getName());
    }
    // many more else branches...
}

执行如下操作:

public interface DungeonFeature {
    void moveInto();
}

public class Wall implements DungeonFeature {
    @Override
    public void moveInto() {
        System.err.println("You bump into a wall");
    }

   // ...
}

public class Person implements DungeonFeature {
    private String name;

    @Override
    public void moveInto() {
        System.err.println("You bump into " + name);
    }

    // ...
}

// and later
public void moveTo(Position pos) {
    DungeonFeature df = currentPosition();
    df.moveTo(pos);
}

这有一些优点。

首先,你不需要在每次添加新的地下城功能时都调整一个巨人树。

其次,地牢中的代码功能是自包含的,逻辑都在所述对象中。您可以轻松测试并移动它。


答案 2

精细的方式删除的理论解决方案是使用访问者模式。它的工作原理是,需要知道另一个元素是墙还是人的对象以自身作为参数调用该对象,并且该特定对象回调从而提供有关其类型的信息。instanceof

public class Person {
    void magic() {
        if(grid.getAdjacent() instanceof Person) {
            Person otherPerson = (Person)grid.getAdjacent();
            doSomethingWith(otherPerson);
        } else if(grid.getAdjacent() instanceof Wall) {
            Wall wall = (Wall)grid.getAdjacent();
            doOtherThingWith(wall);
        }
    }
}

可以成为

public class Person extends Entity {
    void magic() {
        grid.getAdjacent().visit(this);
    }

    void onVisit(Wall wall) {
        doOtherThingWith(wall);
    }

    void onVisit(Person person) {
        doSomethingWith(person);
    }

    public void visit(Person person) {
        person.onVisit(this);
    }
}

public class Wall extends Entity { 
    public void visit(Person person) {
        person.onVisit(this);
    }
}