简体   繁体   English

如何摆脱实例?

[英]How to get rid of instanceof?

I have been told that using instanceof like in the code below is bad practice as it becomes repetitive and makes extension hard.有人告诉我,在下面的代码中使用 instanceof 是不好的做法,因为它变得重复并且难以扩展。 I'm pretty new to Java though and don't see straight away what my alternatives are, what would you recommend I do to get rid of instance of and abstract the code?我对 Java 还是很陌生,但并没有立即看到我的替代方案是什么,你会建议我做些什么来摆脱实例和抽象代码?

void moveit(Vehicle car) {
        if(car instanceof Volvo240){
            volvoPoint.x = (int) car.getXCoordinate();
            volvoPoint.y = (int) car.getYCoordinate();
        }
        if(car instanceof Scania) {
            scaniaPoint.x = (int) car.getXCoordinate();
            scaniaPoint.y = (int) car.getYCoordinate() + 100;
        }
        if(car instanceof Saab95) {
            saabPoint.x = (int) car.getXCoordinate();
            saabPoint.y = (int) car.getYCoordinate() + 200;
        }
        repaint();
    }

InstanceOf's will make it hard to introduce a new type of car. InstanceOf 将使推出新型汽车变得困难。 You will have to find all the places you did these instanceof checks and modify with the new car.您将必须找到您进行这些实例检查并使用新车进行修改的所有位置。 See the "Open for extension and closed for modification" principle.参见“开放扩展,封闭修改”原则。

You should have an interface你应该有一个界面

interface Vehicle {
  Integer getXCoordinate();
  Integer getYCoordinate();
  void moveIt(Point point);
}

And three implementations, Saab95, Volvo240 and Scania以及三种实现方式,Saab95、Volvo240 和 Scania

class Saab95 implements Vehicle {
   moveIt(Point point) {
      point.x = getXCoordinate();
      point.y= getYCoordinate() + 200
   }
}

And so on for the other cars其他车以此类推

Without knowing the complete code, and assuming that you only have those three subclasses.在不知道完整代码的情况下,并假设您只有这三个子类。 The least intrusive approach is to take advantage of method overloading:侵入性最小的方法是利用方法重载:

void moveit(Volvo240 car){
     volvoPoint.x = (int) car.getXCoordinate();
     volvoPoint.y = (int) car.getYCoordinate();
     repaint();
}

void moveit(Scania car){
     volvoPoint.x = (int) car.getXCoordinate();
     volvoPoint.y = (int) car.getYCoordinate() + 100;
     repaint();
}

void moveit(Saab95 car){
     saabPoint.x = (int) car.getXCoordinate();
     saabPoint.y = (int) car.getYCoordinate() + 200;
     repaint();
}

void moveit(Vehicle car){
     repaint();
}

It seems to me that the variables volvoPoint.x and volvoPoint.y should belong to the class Volvo240 (and the same applies to the other variables).在我看来,变量volvoPoint.xvolvoPoint.y应该属于 class Volvo240 (同样适用于其他变量)。 But you kept those variables (that should belong to the classes Volvo240 , Scania , and Saab95 ) in a single place, so that (I would assume) you can repaint based on those variables' values.但是您将这些变量(应该属于Volvo240ScaniaSaab95类)保存在一个地方,以便(我假设)您可以根据这些变量的值repaint

You should consider an alternative approach in which you teach each Vehicle how to repaint themselves.您应该考虑另一种方法,在这种方法中,您Vehicle如何repaint自己。 Hence, moving the repaint logic and those variables to each of the subclasses, accordingly:因此,将repaint逻辑和那些变量移动到每个子类,相应地:

public class Volvo240 extends Vehicle{

       public repaint(){
              volvoPoint.x = (int) car.getXCoordinate();
              volvoPoint.y = (int) car.getYCoordinate();
              // do the repaint logic
       } 
}

I'm going to say right up front, I have no problem with your original solution.我要直接说,我对您的原始解决方案没有任何问题。 More on that at the bottom of this post.更多关于这篇文章底部的内容。 If you really want your current code to work without using instanceof , here's one way.如果您真的希望您当前的代码在不使用instanceof的情况下工作,这是一种方法。

You could make a new class to store the information associated with each type of vehicle, like so:您可以创建一个新的 class 来存储与每种类型的车辆相关的信息,如下所示:

public class VehicleInfo {
    private final Point point;
    private final int offset;

    public VehicleInfo(Point point, int offset) {
        this.point = point;
        this.offset = offset;
    }

    public Point getPoint() {
        return point;
    }

    public int getOffset() {
        return offset;
    }
}

You could then use that class in your method like so:然后,您可以在您的方法中使用该 class ,如下所示:

private static final HashMap<Type, Point> POINT_MAP = new HashMap<Type, Point>() {
    {
        put(Volvo240.class, new VehicleInfo(volvoPoint, 0));
        put(Scania.class, new VehicleInfo(scaniaPoint, 100));
        put(Saab95.class, new VehicleInfo(saabPoint, 200));
    }
};

void moveit(Vehicle car) {
    VehicleInfo info = POINT_MAP.get(car.getClass());
    info.getPoint().x = car.getXCoordinate();
    info.getPoint().y = car.getYCoordinate() + info.getOffset();
    repaint();
}

That said, I really don't have a problem with your original solution using instanceof .也就是说,我真的对您使用instanceof的原始解决方案没有任何问题。 The program is going to have to check the type of the argument at some point, so might as well explicitly show that in your code.该程序将不得不在某个时候检查参数的类型,因此不妨在您的代码中明确显示这一点。 Unless this part of the program is going to be repeatedly modified and this is part of some huge project where everyone needs to use standard coding conventions, I would just stick with what you've got, despite what everyone else here is saying.除非程序的这一部分将被反复修改,并且这是一个每个人都需要使用标准编码约定的大型项目的一部分,否则我会坚持你所拥有的,尽管这里的其他人都在说。 I was recently introduced to the concept of YAGNI , and I think that definitely applies here.我最近被介绍了YAGNI的概念,我认为这绝对适用于此。 If it works, it works.如果它有效,它就有效。

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

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