gpt4 book ai didi

java - 编译时的通用重载

转载 作者:行者123 更新时间:2023-12-01 17:46:20 25 4
gpt4 key购买 nike

是否可以设计一种在编译时调用不同方法重载的方法?

可以说,我有这个小类(class):

@RequiredArgsConstructor
public class BaseValidator<T> {
private final T newValue;
}

现在,我需要返回不同对象的方法(取决于 T)。像这样:

private StringValidator getValidator() {
return new ValidationString(newValue);
}

private IntegerValidator getValidator() {
return new Validation(newValue);
}

最后,我想要一个非常流畅的调用层次结构,如下所示:

new BaseValidator("string")
.getValidator() // which returns now at compile-time a StringValidator
.checkIsNotEmpty();
//or
new BaseValidator(43)
.getValidator() // which returns now a IntegerValidator
.checkIsBiggerThan(42);

在我的“真实”案例中(我有一种非常具体的方法来更新对象,并且每个对象都有很多条件,并且复制粘贴问题的可能性非常高。因此向导强制所有开发人员完全按照这种方式实现。): Ide Image

我尝试了不同的方法。 validator 内的复杂泛型,或者使用泛型。我的最后一个方法如下所示。

public <C> C getValidator() {
return (C) getValidation(newValue);
}

private ValidationString getValidation(String newValue) {
return new StringValidator(newValue);
}

private ValidationInteger getValidation(Integer newValue) {
return new IntegerValidation(newValue);
}

有什么技巧吗?

//编辑:我希望在编译时进行检查,而不是在运行时使用 instanceof 检查。

最佳答案

What is the trick?

不要这样做。

提供静态工厂方法:

class BaseValidator<T> {
static ValidationString getValidation(String newValue) {
return new ValidationString(newValue);
}

static ValidationInteger getValidation(Integer newValue) {
return new ValidationInteger(newValue);
}
}

class ValidationString extends BaseValidator<String> { ... }
class ValidationInteger extends BaseValidator<Integer> { ... }

尽管我认为这很奇怪:您指的是基类内的子类。这种循环依赖使代码难以使用,特别是在重构时,但也可能在初始化时。

相反,我建议创建一个实用程序类来包含工厂方法:

class Validators {
private Validators() {}

static ValidationString getValidation(String newValue) {
return new ValidationString(newValue);
}

static ValidationInteger getValidation(Integer newValue) {
return new ValidationInteger(newValue);
}
}

没有这样的循环。

<小时/>

关于泛型,要认识到的一个非常重要的事情是,它只不过是使显式强制转换成为隐式(然后检查所有这些隐式强制转换是否都是类型安全的)。

换句话说,这个:

List<String> list = new ArrayList<>();
list.add("foo");
System.out.println(list.get(0).length());

只是一种更好的书写方式:

List list = new ArrayList();
list.add((String) "foo");
System.out.println(((String) list.get(0)).length());

同时<String>看起来它是类型的一部分,它基本上只是编译器注入(inject)大量强制转换的指令。

具有不同类型参数的泛型类都具有相同的方法。这是您的方法的具体困难:您无法制作 BaseValidator<String>.getValidator()返回带有 checkIsNotEmpty 的内容方法(仅),以及 BaseValidator<Integer>.getValidator()返回带有 checkIsGreaterThan 的内容方法(仅限)。

嗯,这并不完全正确,不能。当您尝试涉及方法范围的类型变量( <C> C getValidator() )时,您可以编写:

new BaseValidator<>("string").<StringValidator>getValidator().checkIsNotEmpty()

(假设 StringValidatorcheckIsNotEmpty 方法)

但是:

  • 我们不要拐弯抹角:它很丑。
  • 比丑陋更糟糕的是,它不是类型安全的。你同样可以这样写:

    new BaseValidator<>("string").getValidator().checkIsGreaterThan(42)

    这是无意义的,但编译器允许。问题是返回类型是在调用站点选择的:您要么必须返回 null(当您尝试调用以下方法时,会得到 NullPointerException);或返回一些非空值并冒 ClassCastException 的风险。无论哪种方式:都不好。

但是,您可以做的是使通用 validator 成为方法调用的参数。例如:

interface Validator<T> {
void validate(T b);
}

class BaseValidator<T> {
BaseValidator<T> validate(Validator<T> v) {
v.validate(this.value);
}
}

并像这样调用,演示如何链接方法调用以应用多个验证:

new BaseValidator<>("")
.validate(s -> !s.isEmpty())
.validate(s -> s.matches("pattern"))
...

new BaseValidator<>(123)
.validate(v -> v >= 0)
...

关于java - 编译时的通用重载,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54788992/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com