我有以下类/接口结构(无法修改源):
public interface Car {}
public class CarA implements Car{
public String getASpecifics() {...}
}
public class CarB implements Car{
public String getBSpecifics() {...}
}
public class Summary {...}
我想有一个通用的创建方法 Summray
具体实现 Car
接口,该接口将对添加新实现开放。我的做法如下:
public CarSummarizer {
public interface SummaryGenerator<T extends Car> {
Summary generateSummary(T car);
}
static {
SummaryGenerator<CarA> aGen = c -> {... c.getASpecifics(); ...}
SummaryGenerator<CarB> bGen = c -> {... c.getBSpecifics(); ...}
}
}
现在我想去商店 aGen
及 bgen
在一个 Map
. 我想对它进行参数化,这样我就可以提供一个唯一可以接受的公共静态方法 Car car
并且基于它的类对象( car.getClass()
)使用正确的 SummaryGenerator
实施。这应该如下所示:
public static Summary getSummaryForCar(Car car) {
return map.get(car.getClass()).generateSummary(car);
}
我不知道如何声明和示例化它 Map
因此它是完全类型安全的(即不允许插入对 (CarC.class, SummaryGenerator<CarD>)
). 我想要这样的东西:
public static <T extends Car> Map<Class<T>, SummaryGenerator<T>> map = new LinkedHashMap<>();
static {
// after instantiation
map.put(CarA.class, aGen);
map.put(CarB.class, BGen);
}
// also support following
public static <T extends Car> void addSummaryGenerator(T car, SummaryGenerator<T> sg) {
map.put(car.getClass(), sg);
}
这是行不通的,因为泛型不能像在函数上一样在变量上声明。我想我可以定义新的类 public class SummarizerStorage<T extends Car>
和内部的位置Map,只需代理调用。这似乎是一种矫枉过正和丑陋的行为。我觉得应该直接做。
声明类Map Map<Class<? extends Car>, SummaryGenerator<? extends Car>>
允许切割 Class<>
及 SummaryGenerator<>
兄弟姐妹类型。我只允许相同类型的对。
1条答案
按热度按时间lzfw57am1#
如果 Package Map并且只允许放置值为
SummaryGenerator<T>
匹配Class<T>
. 得到SummaryGenerator
您需要强制转换,但由于您确保只添加了实际上可以强制转换到的条目SummaryGenerator<T>
,这样做是安全的。如果您试图添加不兼容的SummaryGenerator
对于给定的实现Car
,这将导致编译错误。为了得到一个
Summary
,则检索已注册的SummaryGenerator
对于Car
并致电generateSummary
方法。如果没有SummaryGenerator
为已通过的实现找到Car
,只需抛出一个异常或以不同的方式处理它。请注意add
需要Class
而不是Car
对象,因为此时不需要示例来引用的实现Car
.下面是上述代码的测试类。简单的
Summary
使用了包含名称字段的Car
在其字段中返回a、b或cgetXSpecifics()
方法:对于其他类别的完整性: