当对象是基础的实例时,为对象调用正确的方法 class

Calling the correct method for an object, when the object is an instance of a base class

我在 Java 中有以下示例:

public abstract class Vehicle {
    private final String name;
    private final String make;

    public Vehicle(final String name, final String make) {
        this.make = make;
        this.name = name;
    }
}

public final class Car extends Vehicle {
    public Car(final String name, final String make) {
        super(name, make);
    }
}

public final class Truck extends Vehicle  {
    final Integer grossVehicleWeight;

    public Truck(final String name, final String make, final Integer gvw) {
        super(name, make);
        this.grossVehicleWeight = gvw;
}

说我想用载具做一些工作,而这个工作不依赖于载具的子class。所以,我在另一个 class 中有一个这样的方法:

public void doStuff(public final Vehicle vehicle) {
    //do stuff here
    //then insert it into my database:
    insertVehicle(vehicle);
}

但是,我想在我的 insertVehicle 中做不同的事情,所以我为每个子重写该方法class:

public void insertVehicle(Car car) { //do stuff for a car }

public void insertVehicle(Truck truck) { //do stuff for a truck }

在我的 doStuff 方法中,我可以使用 instanceOf 来确定车辆(Car 或 Truck)的 class,然后将车辆投射到 class 中并像这样调用 insertVehicle 方法:

public void doStuff(public final Vehicle vehicle) {
    //do stuff here
    //then insert it into my database:
    if (vehicle instanceof Car) {
        insertVehicle((Car) vehicle);
    } else {
        insertVehicle((truck) vehicle);
    }
}

但是,我了解到使用 instanceof 并不是执行此操作的最佳方法。 1

我怎样才能最好地修改它以便我不必使用 instanceof?

您可以使用访问者模式:

public interface VehicleVisitor {
    public void visit(Car car);
    public void visit(Truck truck);
}

public class Car extends Vehicle {

    @Override
    public void insert(VehicleVisitor vehicleVisitor) {
        vehicleVisitor.visit(this);
    }
}

public class Truck extends Vehicle {
    @Override
    public void insert(VehicleVisitor vehicleVisitor) {
        vehicleVisitor.visit(this);
    }
}

public abstract class Vehicle {
    public abstract void insert(VehicleVisitor vehicleVisitor);
}

public class VehicleVisitorImpl implements VehicleVisitor {

    @Override
    public void visit(Car car) {
        System.out.println("insert car");
    }

    @Override
    public void visit(Truck truck) {
        System.out.println("insert truck");
    }
}

public class Main {

    public static void main(String[] args) {
        Vehicle vehicle = new Car();
        // finally the agnostic call
        vehicle.insert(new VehicleVisitorImpl());
    }

}

你可以为

制作车辆内部的抽象函数
public abstract void doStuff()

从您要修改的对象的实例调用此函数

ford.doStuff();     //ford is car instance 

然后就可以用这个修改了

doStuff()
{
    this.cost += 10;
}

否则,您可以为 vehicle 添加一个变量,指示车辆类型是什么 return。喜欢:

  public void doStuff(public final Vehicle vehicle) {
       //do stuff here
       //then insert it into my database:
       if (vehicle.getType()== 'Car') {
            insertVehicle((Car) vehicle);
        } else {
            insertVehicle((truck) vehicle);
        }
   }

这个变量 'vehicleType' 将在车辆 class 中并将在构造函数中初始化:

  public final class Car extends Vehicle {
       public Car(final String name, final String make, final String vehicleType) {
             super(name, make, type);
        }
    }

一种方法是在 Vehicle 中使用 insertVehicle() 方法抽象。然后在子类 CarTruck.

中实现它们

但是,这会将逻辑移动到 POJO 中。也许最好将 db-logic 与 POJO 分开,即在这种情况下只使用 instanceof

public abstract class Vehicle {
    private final String name;
    private final String make;

    public Vehicle(final String name, final String make) {
        this.make = make;
        this.name = name;
    }

    public abstract void insertVehicle();
}

public final class Car extends Vehicle {
    public Car(final String name, final String make) {
        super(name, make);
    }

    public void insertVehicle() {

    }
}

public final  class Truck extends Vehicle {
    final Integer grossVehicleWeight;

    public Truck(final String name, final String make, final Integer gvw) {
        super(name, make);
        this.grossVehicleWeight = gvw;
    }

    public void insertVehicle() {

    }
}

public void doStuff(Vehicle vehicle) {
    //do stuff here
    //then insert it into my database:
    vehicle.insertVehicle();
}

这取决于您要解决的问题类型。如果是持久性,请确保您没有重新发明 JPA. If it is type-specific processing then you can solve it as @denis suggested. Or if you want to keep entities in POJO-style you can use strategy pattern,例如:

Map<Class<?>, Consumer<Vehicle>> consumers;
{
    consumers.put(Car.class, v -> insertVehicle((Car)v));
    consumers.put(Truck.class, v -> insertVehicle((Truck)v));
}
public void doStuff(public final Vehicle vehicle) {
    //do stuff here
    consumers
      .get(vehicle.getClass())
      .accept(vehicle);
}

如果您不喜欢将 doStuff() 放入 CarTruck,您可以为它们每个设置一个 doStuff() 方法,并将通用的 Vehicle逻辑转换成另一种方法。

private void doCommonStuff(final Vehicle vehicle) {
    //do stuff here
}

public void doStuff(final Car car) {
    doCommonStuff(car);
    //then insert it into my database:
    insertVehicle(car);
}

public void doStuff(final Truck truck) {
    doCommonStuff(truck);
    //then insert it into my database:
    insertVehicle(truck);
}

不过,我们可以使用泛型做得更好。

public abstract class StuffDoer<T extends Vehicle> {
  public void doStuff(final T vehicle) {
    // do stuff here
    // then insert it into my database:
    insertVehicle(vehicle);
  }

  public abstract void insertVehicle(T vehicle);
}

public class CarStuffDoer extends StuffDoer<Car> {
  public void insertVehicle(Car car) {
    // whatever
  }
}

public class TruckStuffDoer extends StuffDoer<Truck> {
  public void insertVehicle(Truck truck) {
    // whatever else
  }
}