假设我有这样的界面;
interface Validator<T>{
void validate<T value>
}
这些实施;
class StringValidator implements Validator<String>{
void validate<String value>{}
}
class OrderValidator implements Validator<Order>{
void validate<Order value>{}
}
在ValidatorRegisterer类中,我有一张地图;
class ValidationRegisterer{
Map<String, Validator> validatorsForPath = new HashMap<String, Validator>();
public Map<String, Validator> registerers(){
return validatorsForPath;
}
public void register(String path, Validator validator){
validatorsForPath.put(path, validator);
}
}
我想要的是在ValidationManager类中使用类型安全迭代这个地图;
class ValidationManager<RootObject>{
List<ValidationRegisterer> validationRegisterers;
public ValidationManager(List<ValidationRegisterer> validationRegisterers){
this.validationRegisterers = validationRegisterers;
}
public void validate(RootObject object){
for(ValidationRegisterer validationRegisterer in validationRegisterers){
for(String path : validationRegisterer.keySet()){
Object value = object.getPath(path);
Validator validator = validationRegisterer.get(path);
validator.validate(value);
//this line gets unchecked call to validate(T) warning and I want to get rid of it
//the problem is validationRegisterers map can contain both StringValidator and OrderValidator,
//so the value can be a String or an Order
//do I have to cast the value to the type of validator's T type?
}
}
}
Map<String, Validator> validatorsForPath = new HashMap<String, Validator>();
}
我试着在最后的代码示例注释中解释这种情况。
答案 0 :(得分:0)
声明如下以删除警告:
Validator<Object> validator = validationRegisterer.get(path);
在这种情况下,您将声明可用于对象类型的验证程序引用。 之后,您可以在执行测试实例后对类型或字符串进行类型转换。
答案 1 :(得分:0)
您需要将ValidationRegisterer类设为通用,如下所示:
class ValidationRegisterer<T extends Validator> {
Map<String, T> validatorsForPath = new HashMap<String, T>();
public Map<String, T> registerers(){
return validatorsForPath;
}
public void register(String path, T validator){
validatorsForPath.put(path, validator);
}
}
然后为这两种类型的ValidationRegisterer
维护单独的列表class ValidationManager {
List<ValidationRegisterer<StringValidator>> strValidationRegisterers;
List<ValidationRegisterer<OrderValidator>> ordValidationRegisterers;
....
}
答案 2 :(得分:0)
我将假设“类型安全”是指您希望确定为特定路径返回的对象实际上是关联的Validator
接受的类型。
一个问题是Validator
的类型参数在编译时不可用,因为正如您所说,任何类型的Validator
都可以在地图中。
此外,object.getPath(path)
将始终返回Object
,它始终需要在运行时进行转换,因此validate
方法将其参数限制为类型T
的事实是很少使用。
因此,如果对象的类型不正确,那么您可以做的最好的事情就是快速验证失败。
解决方案是
1.存储Class
的{{1}}对象,
2.让Validator
接受validate
作为参数,并在validate方法的开头动态地将对象转换为验证器类型。这可以在抽象基类中完成。
示例:
Object
如果要将interface Validator<T> {
void validate(Object value);
Class<T> getType();
}
abstract class BaseValidator<T> implements Validator<T> {
private final Class<T> type;
public BaseValidator(Class<T> type) {
this.type = type;
}
public final void validate(Object o) {
doValidate(type.cast(o)); // wrong type will fail fast here
}
public final Class<T> getType() {
return type;
}
protected abstract void doValidate(T value);
}
class StringValidator extends BaseValidator<String> {
public StringValidator() {
super(String.class);
}
protected void doValidate(String value) {
// do actual string validation here
}
}
保留在Object
接口之外,另一种解决方案是让路径通过类型参数化对象解析,该对象具有引用验证器并执行动态转换,并将其作为值保存在注册表映射中:
Validator
然后,您的interface Validator<T> {
void validate(final T value);
}
class PathValidator<T> {
private final Class<T> type;
private final Validator<T> validator;
public PathValidator(final Class<T> type, final Validator<T> validator) {
this.type = type;
this.validator = validator;
}
public void validate(final RootObject object, final String path) {
T value = type.cast(object.getPath(path)); // throws ClassCastException here if not the correct type
validator.validate(value);
}
}
课程中会有Map<String, PathValidator<?>
。
我个人更喜欢这种替代解决方案。