避免显式转换的最佳方法

时间:2015-12-08 09:31:49

标签: java inheritance design-patterns casting polymorphism

我有一个类层次结构,如下面的

Vehicle
|_ TransaportationVehicle has method getLoadCapacity
|_ PassengerVehicle has method getPassengerCapacity

我还有一个课程Booking,它引用了Vehicle

现在每当我必须在getPassengerCapacity引用上致电getLoadCapacityvehicle时,我需要输入类似于((PassengerVehicle)vehicle).getPassengerCapacity()的具体实施方案,并且这种类型的调用跨越项目中的多个部分。那么有什么方法可以避免这些类型的演员表,我的代码会看起来漂亮干净吗?

注意:这些不是我用这些作为示例来演示当前问题的实际类。

7 个答案:

答案 0 :(得分:3)

显然,在预订Vehicle时,您需要在某个时候区分它是TransportationVehicle还是PassengerVehicle,因为两者都有不同的属性。

最简单的方法是启动两个不同的Booking流程:一个用于可以运输货物的车辆,另一个用于可以运送乘客的车辆。至于如何区分这两种类型的车辆:您可以将canTransportPassengers()canTransportGoods()方法添加到Vehicle,然后子类将覆盖这些方法以在适当的位置返回true 。此外,通过这种方式,可以像火车一样运输两者。

答案 1 :(得分:2)

如果要使用不同的方法名称,则必须转换为具体类。

但是,如果您可以使此方法返回相同的类型值并具有相同的名称您可以使用多态。在Vehicle类中创建抽象方法并在每个子项中覆盖它。

答案 2 :(得分:2)

我要做的就是快速创建一个Generified Booking父类。

public abstract class Booking<V extends Vehicle> {

    protected abstract V getVehicle();
}

public class TransportationVehicleBooking extends Booking<TransaportationVehicle> {

    @Override
    protected TransaportationVehicle getVehicle() {
        return new TransaportationVehicle();
    }
}

public class PassengerVehicleBooking extends Booking<PassengerVehicle> {

    @Override
    protected PassengerVehicle getVehicle() {
        return new PassengerVehicle();
    }
}

您的Booking类将具有跨越所有预订子类的所有逻辑以及每个子类进行有效计算所需的抽象方法。

然后,您所要做的就是参考Booking课程并调用所需的相关方法,而不必担心&#34;物流&#34; (得到它)预订本身。

我希望这会有所帮助。

答案 3 :(得分:1)

您的方法覆盖概念。您需要在Parent类中拥有所有这些方法,并且可以在子子句中覆盖相同的方法。

然后,您可以使用Runtime polymorphism

从超类访问所有方法

<强>车辆

public interface Vehicle {
    public int getCapacity();
}

TransaportationVehicle

public class TransaportationVehicle implements Vehicle {

    @Override
    public int getCapacity() {
        return getLoadCapacity();
    }

    private int getLoadCapacity() {
        return 0;
    }

}

PassengerVehicle

public class PassengerVehicle implements Vehicle {

    @Override
    public int getCapacity() {
        return getPassengerCapacity();
    }

    private int getPassengerCapacity() {
        return 0;
    }
}

<强> USAGE

Vehicle passenger = new PassengerVehicle();
passenger.getCapacity();

Vehicle transaportation = new TransaportationVehicle();
transaportation.getCapacity()

答案 4 :(得分:0)

假设乘客容量总是一个整数,负载容量可能很大,取决于负载的单位。我会继续创建Vehicle类,如下所示:

class Vehicle {
    Number capacity; 
    public Number getCapacity() {
        return capacity; 
    }
    public void setCapacity(Number capacity) {
        this.capacity = capacity; 
    }
}

我使用Number的原因是,我在PassengerVehicle类中使用Integer,在TransporatationVehicle中使用Double,这是因为IntegerDoubleNumber的子类型,你可以通过演员表逃脱。

class TransportationVehicle extends Vehicle {
    @Override 
    public Double getCapacity() {
        //all I have to do is cast Number to Double
        return (Double) capacity; 
    }

    @Override 
    public void setCapacity(Number capacity) {
        this.capacity = capacity; 
    }
}

类似于PassengerVehicle类如下:

class PassengerVehicle extends Vehicle {
    @Override 
    public Integer getCapacity() {
        //Cast to Integer and works because Integer is subtype of Number
        return (Integer) capacity; 
    }

    @Override 
    public void setCapacity(Number capacity) {
        this.capacity = capacity; 
    }
}

然后,您可以使用上面的类来创建车辆对象,如下所示:

public class Booking {
    public static void main(String[] args) {
        //
        Vehicle transportationVehicle = new TransportationVehicle();
        //assigning Double to setCapacity
        transportationVehicle.setCapacity(new Double(225.12));


        Vehicle passengerVehicle = new PassengerVehicle(); 
        //assigning Integer to setCapacity
        passengerVehicle.setCapacity(5);

        System.out.println(transportationVehicle.getCapacity()); 
        // output: 225.12
        System.out.println(passengerVehicle.getCapacity());
        // output: 5
    }
}

在旁边的注释中,如果你尝试传递TransportationVehicle除了Number或Double之外的任何东西,那么你将得到Exception,同样如果你传递PassengerVehicle除了Number或Integer以外的任何东西,你将获得异常。

我知道我偏离了你的问题的范围但是,我真的想要展示你如何使你的方法泛化。这允许您决定在编码期间返回getCapacity()的类型,这是非常灵活的。见下文:

class Vehicle<T> {
    //generic type T
    T capacity; 

    //generic method getCapacity
    public T getCapacity() {
        return capacity; 
    }

    //generic method setCapacity 
    public void setCapacity(T capacity) {
        this.capacity = capacity; 
    }
}

class TransportationVehicle<T> extends Vehicle<T> {
    @Override 
    public T getCapacity() {
        return capacity; 
    }

    @Override 
    public void setCapacity(T capacity) {
        this.capacity = capacity; 
    }
}

class PassengerVehicle<T> extends Vehicle<T> {
    @Override 
    public T getCapacity() {
        return capacity; 
    }

    @Override 
    public void setCapacity(T capacity) {
        this.capacity = capacity; 
    }
}

正如您在上面看到的泛型方法,您可以按照以下方式使用它们:

Vehicle<String> vehicleString = new TransportationVehicle<String>();
vehicleString.setCapacity("Seriously!"); //no problem

Vehicle<Integer> vehicleInteger = new PassengerVehicle<Integer>(); 
vehicleInteger.setCapacity(3); //boxing done automatically

Vehicle<Double> vehicleDouble = new PassengerVehicle<Double>(); 
vehicleDouble.setCapacity(2.2); //boxing done automatically  

您可以在编码时决定类型,如果您提供容量为Vehicle<String>的{​​{1}},那么您将收到编译时错误,因此您将不被允许。

Integer

答案 5 :(得分:0)

首先尝试提取适合所有车辆的抽象方法。如果你不能这样做,你也可以使用一个经常被遗忘的模式 - visitor pattern。 E.g。

介绍访客界面

public interface VehicleVisitor {
    public void visit(TransportationVehicle transportationVehicle);
    public void visit(PassengerVehicle passengerVehicle);
}

accept

添加Vehicle方法
public interface Vehicle {
    public void accept(VehicleVisitor visitor);
}

在子类中实现accept方法

public class PassengerVehicle implements Vehicle {

    private int passengerCapacity;

    public static PassengerVehicle withPassengerCapacity(int passengerCapacity) {
        return new PassengerVehicle(passengerCapacity);

    }

    private PassengerVehicle(int passengerCapacity) {
        this.passengerCapacity = passengerCapacity;
    }

    public int getPassengerCapacity() {
        return passengerCapacity;
    }

    @Override
    public void accept(VehicleVisitor visitor) {
        visitor.visit(this);

    }
}

public class TransportationVehicle implements Vehicle {

    private int loadCapacity;

    public static TransportationVehicle withLoadCapacity(int loadCapacity) {
        return new TransportationVehicle(loadCapacity);

    }

    private TransportationVehicle(int loadCapacity) {
        this.loadCapacity = loadCapacity;
    }

    public int getLoadCapacity() {
        return loadCapacity;
    }

    @Override
    public void accept(VehicleVisitor visitor) {
        visitor.visit(this);
    }
}

实施访客...

public class LoadSupported implements VehicleVisitor {

    private boolean supported;
    private int load;

    public LoadSupported(int load) {
        this.load = load;
    }

    public boolean isSupported() {
        return supported;
    }

    @Override
    public void visit(TransportationVehicle transportationVehicle) {
        int loadCapacity = transportationVehicle.getLoadCapacity();
        supported = load <= loadCapacity;

    }

    @Override
    public void visit(PassengerVehicle passengerVehicle) {
        supported = false;
    }

}

...并使用它

public class Main {

    public static void main(String[] args) {
        TransportationVehicle transportationVehicle1 = TransportationVehicle
                .withLoadCapacity(5);
        TransportationVehicle transportationVehicle2 = TransportationVehicle
                .withLoadCapacity(10);
        PassengerVehicle passengerVehicle = PassengerVehicle
                .withPassengerCapacity(5);

        LoadSupported loadSupported = new LoadSupported(7);

        supportsLoad(transportationVehicle1, loadSupported);
        supportsLoad(transportationVehicle2, loadSupported);
        supportsLoad(passengerVehicle, loadSupported);

    }

    private static void supportsLoad(Vehicle vehicle,
            LoadSupported loadSupported) {
        vehicle.accept(loadSupported);
        System.out.println(vehicle.getClass().getSimpleName() + "[" + System.identityHashCode(vehicle) + "]" + " does"
                + (loadSupported.isSupported() ? " " : " not ")
                + "support load capacity");
    }
}

输出将是这样的

TransportationVehicle[778966024] does not support load capacity
TransportationVehicle[1021653256] does support load capacity
PassengerVehicle[1794515827] does not support load capacity

答案 6 :(得分:0)

我不理解这个例子。您如何意识到您首先要处理的是混凝土类型?你是实例吗?你打字匹配吗?

如果是这样,你的问题就会过去......

无论如何,如果您拥有必须属于同一系列的对象和非抽象的算法并根据所处理的对象进行更改,则通常会使用某种behavioral pattern类似访问者或Bridge pattern