繁体   English   中英

Java - 如何将未知的接口实现传递给泛型方法

[英]Java - How to pass unknown implementation of interface to generic method

我有这样的问题(当然这只是一个例子)。 我有处理器,我必须在那里修理汽车。 我有一个字符串作为汽车对象的 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 根据“类型”值实例化什么。

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

}

您可以通过以下组合来达到您的结果:

  • 杰克逊儿童类的反序列化
  • 您的服务站的访客模式

服务站

这是实现的“访问者”部分。

你应该有一个单一的实现,为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抽象类及其实现

这将是您实现的“访问”部分。

您将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)
    }

}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM