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

时间:2016-03-21 19:52:37

标签: java polymorphism subclassing

我在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;
}

假设我想用车辆做一些工作,而且工作不依赖于车辆的子类。所以,我在另一个类中有一个方法,如下所示:

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

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

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

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

在我的doStuff方法中,我可以使用instanceOf来确定车辆的类别(Car或Truck),然后将车辆投射到该类并调用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?

5 个答案:

答案 0 :(得分:3)

您可以使用访客模式:

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());
    }

}

答案 1 :(得分:3)

您可以在车辆内部进行抽象功能

public abstract void doStuff()

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

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

然后您可以使用此进行修改。

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

否则,您可以为车辆添加一个变量,指示车辆类型是什么并将其返回。像:

  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'将在车辆类中,并将在构造函数内初始化:

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

答案 2 :(得分:1)

这取决于您尝试解决的问题类型。如果是持久性,请确保您没有重新发明JPA。如果是特定类型的处理,那么你可以像@denis建议的那样解决它。或者如果你想保持POJO风格的实体,你可以使用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);
}

答案 3 :(得分:0)

一种方法是在insertVehicle()中使用Vehicle方法摘要。然后在子类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();
}

答案 4 :(得分:0)

如果您不想将Car放入TruckdoStuff(),那么您可以为每个人提供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); } {1}}逻辑转换为另一种方法。

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
  }
}

但是,我们可以用泛型做得更好。

X = c(0,1,2,3,4,5)
Y = c("abc", "def", "ghi")
b = data.frame(X, Y)