使用泛型时避免强制转换

Fri*_*jof 4 java generics

在一个项目中,我有一个服务和一个使用该服务的类。在此示例中,车辆将使用维修服务。维修服务只能维修某种类型的车辆:车库只能维修汽车。我需要一种方法来通过适用的服务来修理车辆repairUsingService(..)

我的目标是拥有一个干净的Vehicle基类和干净的RepairService实现。我尝试了两种设计repair维修服务的方法:

  • repair(Vehicle<T> vehicle):这很丑陋,因为需要实现repair(Vehicle<Car> car),但很明显汽车是一种交通工具。
  • repairSimple(T vehicle):这很好,但Vehicle如果没有丑陋的演员阵容,就无法从班级中调用。

有没有办法避免强制转换但仍然只使用通用参数类型T(如repairSimple(T)

public class Vehicle<T extends Vehicle<T>> {

    public void repairUsingService(RepairService<T> obj) {
        obj.repair(this);
        obj.repairSimple((T) this);
    }
}

public class Car extends Vehicle<Car> {
}

public interface RepairService<T extends Vehicle<T>> {

    void repair(Vehicle<T> vehicle);

    void repairSimple(T vehicle);
}

public class Garage implements RepairService<Car> {
    @Override
    public void repair(Vehicle<Car> car) {
        System.out.println("Car repaired.");
    }

    @Override
    public void repairSimple(Car car) {
        System.out.println("Car repaired.");
    }
}
Run Code Online (Sandbox Code Playgroud)

Apo*_*psa 5

你能使用这个实现吗?这样,车辆就知道哪些维修服务可以维修它,服务也知道它可以维修哪些车辆。

public interface RepairService<T extends Vehicle<?>> {
    public void repair(T vehicle);
}

public interface Vehicle<T extends RepairService<?>> {
    public void repairUsingService(T service);
}

public class Car implements Vehicle<Garage> {
    @Override
    public void repairUsingService(Garage service) {
    }
}

public class Garage implements RepairService<Car>{
    @Override
    public void repair(Car vehicle) {
    }
}

public class AuthorizedGarage extends Garage {

}


public class Train implements Vehicle<TrainDepot> {
    @Override
    public void repairUsingService(TrainDepot service) {

    }

}

public class TrainDepot implements RepairService<Train> {
    @Override
    public void repair(Train vehicle) {

    }

}

public class Test {

    public static void main(String[] args) {

        // this works:
        new Car().repairUsingService(new Garage());
        new Train().repairUsingService(new TrainDepot());

        // and this works
        new Garage().repair(new Car());
        new TrainDepot().repair(new Train());

        // but this does not (which is ok)
        //new Garage().repair(new Train());
        //new Car().repairUsingService(new TrainDepot()); 

        // this also works
        List<Car> cars = new ArrayList<>();
        cars.add(new Car());
        cars.get(0).repairUsingService(new Garage());

        // this also works, if you have an expensive car ;)
        new Car().repairUsingService(new AuthorizedGarage());

    }

}
Run Code Online (Sandbox Code Playgroud)

您甚至可以为所有维修服务建立一个基类,以避免代码重复:

public abstract class BaseRepairService<T extends Vehicle<?>> implements 
RepairService<T> {

    @Override
    public void repair(T vehicle) {

    }

}
Run Code Online (Sandbox Code Playgroud)

然后,您的 Garage 将使用 Car 类型参数扩展 BaseRepairService。