如何解决Java - 如何将未知的接口实现传递给泛型方法
我有这样的问题(当然这只是一个例子)。我有处理器,我必须在那里修理汽车。我有一个字符串作为汽车对象的 json。我不知道 ServiceStation 的实现,我只有汽车实现类。我必须将 json 解析为汽车对象并将其提供给服务站。有什么合适的解决方案可以实现这一目标吗?
public interface Car {}
public class BMW implements Car {}
public interface ServiceStation<T extends Car> {
public void repair(T car)
}
public class BMWServiceStation<BMW> {
public void repair(BMW car) { ... }
}
public class ServiceStationProcessor {
public void process(String carJson,Settings settings) {
Class<? extends Car> carClass = settings.getCarClass();
ServiceStation serviceStation = settings.getServiceStation();
JavaType javaType = objectMapper.getTypeFactory().constructType(carClass);
Object<? extends Car> obj = objectMapper.readValue(carJson,javaType); <-- ?? something like this?
serviceStation.repair(obj)
}
}
解决方法
您可以在 json 中有一个“type”字段,用于标识具体的 Car 子类型(例如“bmw”或“mazda”)。然后你可以在 Car 界面上使用注解来告诉 Jackson 根据“type”值实例化什么。
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME,include = JsonTypeInfo.As.PROPERTY,property = "type")
@JsonSubTypes({
@JsonSubTypes.Type(value = BMW.class,name = "bmw"),@JsonSubTypes.Type(value = Mazda.class,name = "mazda")
})
@JsonIgnoreProperties(ignoreUnknown = true)
public interface Car {
}
然后它是类型安全的并且处理器中的逻辑简化了:
public class ServiceStationProcessor {
public void process(String carJson,Settings settings) {
ServiceStation serviceStation = settings.getServiceStation();
Car obj = objectMapper.readValue(carJson,Car.class);
serviceStation.repair(obj);
}
}
,
您可以通过以下组合达到您的结果:
- Jackson 对子类进行反序列化
- 服务站的访客模式
服务站
这是实现的“访问者”部分。
您应该有一个实现为 N
不同的具体类型公开 N
方法(而不是具有 N
相同单方法接口的不同实现)。
像这样:
public interface ServiceStation {
void repair(Bmw bmw);
void repair(Mercedes mercedes);
}
//Single implementation with a dedicated method per type of car
public class ServiceStationImpl implements ServiceStation {
@Override
public void repair(Bmw bmw) {
System.out.println("Repair bmw");
}
@Override
public void repair(Mercedes mercedes) {
System.out.println("Repair mercedes");
}
}
汽车抽象类及其实现
这将是您实施的“访问”部分。
您将 Car
定义为 interface
。
Jackson 允许反序列化子类型,但使用 abstract class
而不是 interface
。
另外,我有机会添加一个接受 ServiceStation
的抽象方法。这将允许每个具体的汽车实现让 ServiceStation(访问者)“访问”自己(被访问者):
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME,property = "type")
@JsonSubTypes(
{
@JsonSubTypes.Type(value = Bmw.class,name = "Bmw"),@JsonSubTypes.Type(value = Mercedes.class,name = "Mercedes")
}
)
public abstract class Car {
public abstract void accept(ServiceStation serviceStation);
}
public final class Bmw extends Car {
@JsonIgnore
private final String type = "Bmw";
@Override
public void accept(ServiceStation serviceStation) {
serviceStation.repair(this); //<-- will call the Bmw method of the service station
}
}
public final class Mercedes extends Car {
@JsonIgnore
private final String type = "Mercedes";
@Override
public void accept(ServiceStation serviceStation) {
serviceStation.repair(this); //<-- will call the Mercedes method of the service station
}
}
主代码
到这里,就变得这么简单了:
public class ServiceStationProcessor {
public void process(String carJson,Settings settings) throws JsonProcessingException {
Class<? extends Car> clazz = settings.getCarClass(); //<-- get the car class as you already do
ServiceStation serviceStation = settings.getServiceStation(); //<-- get the service station
objectMapper.readValue(carJson,clazz).accept(serviceStation); //<-- deserialize the json into the concrete car class (Jackson will pick the right type of car),then ask the car to accept the service station (the car will dispatch to the correct type)
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。