在一个项目中,我有一个使用该服务的服务和一个类。在本例中,车辆将使用的维修服务。维修服务只能修理某一类型的车辆:车库只能修理汽车。我需要一种方法在车辆上修理它与一个适用的服务,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.");
}
}发布于 2015-02-08 13:20:26
您能使用这个实现吗?通过这种方式,车辆知道什么维修服务可以修理它,服务知道什么车辆可以修理。
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());
}
}您甚至可以为您的所有修复服务创建一个基类,以避免代码重复:
public abstract class BaseRepairService<T extends Vehicle<?>> implements
RepairService<T> {
@Override
public void repair(T vehicle) {
}
}然后,您的车库将扩展一个带有汽车类型参数的BaseRepairService。
发布于 2015-02-08 12:50:07
一种方法是自问子类:
abstract class Vehicle<T extends Vehicle<T>> {
public void repairUsingService(RepairService<T> obj) {
obj.repair(this);
obj.repairSimple(getThis());
}
abstract T getThis();
}
class Car extends Vehicle<Car> {
@Override
Car getThis(){
return this;
}
}发布于 2015-02-09 05:43:11
让我提出两个合理的方案。
第一个是加弗氏小工具的变体。
public abstract class Vehicle<V extends Vehicle<V>> {
private boolean validate() {
Class<?> cls = getClass();
for(Class<?> sup;
(sup = cls.getSuperclass()) != Vehicle.class;
cls = sup
);
Type sup = cls.getGenericSuperclass();
if(!(sup instanceof ParameterizedType))
return false;
Type arg = ((ParameterizedType)sup).getActualTypeArguments()[0];
if(!(arg instanceof Class<?>))
return false;
return ((Class<?>)arg).isInstance(this);
}
protected Vehicle() {
assert validate() : "somebody messed up";
}
}因为Vehicle总是由子类参数化,所以使用这个成语是可以的。在开发过程中,您使用断言运行,如果有人不正确地扩展类,构造函数将抛出一个错误。
现在,未检查的转换始终是安全的。
第二种情况是,RepairService不再带有类型参数。相反,您保留了一个Class<? extends Vehicle>的清单,RepairService可以修复。
public interface RepairService {
boolean canRepair(Vehicle v);
// if v can't be repaired, perhaps repair
// throws an exception or returns boolean instead of void
void repair(Vehicle v);
}
public class ServiceStation implements RepairService {
private final List<Class<? extends Vehicle>> types;
public ServiceStation(Class<? extends Vehicle>... types) {
this.types = Arrays.asList(types);
}
@Override
public boolean canRepair(Vehicle v) {
for(Class<? extends Vehicle> c : types) {
if(c.isInstance(v))
return true;
}
return false;
}
@Override
public void repair(Vehicle v) {
if(!canRepair(v))
throw new IllegalArgumentException();
// impl
}
}至少对于Vehicle/RepairStation的类比来说,这可能比试图将泛型强制引入到设计中要有用得多。Vehicle可能也不再需要类型参数了。
也许您的实际程序是不同的,但是在引入参数化设计之前,您应该始终考虑直接的程序逻辑是否解决了这个问题。试图强迫泛型在它们是次优解决方案的情况下工作是非常尴尬的。
https://stackoverflow.com/questions/28393626
复制相似问题