链接、返回基对象以及与扩展类的类型不匹配
我遇到过这样的课程.它拥有一个with"方法,可以让人们将事物链接在一起.
I have come across a class like this. It holds a "with" method that lets people chain things together.
public class Bear {
protected List<String> names = new ArrayList<String>();
protected List<String> foods = new ArrayList<String>();
public Bear withName(String name) {
names.add(name);
return this;
}
public Bear withFood(String food) {
foods.add(food);
return this;
}
}
// ...somewhere else
Bear b = new Bear().withName("jake").withName("fish");
我发现两个类共享 90% 的相同代码.因此,我在它们之间创建了一个基类,并将大约 25 个with"方法转移给它(包括成员变量和所有).就像这样:
I found two classes that shared 90% of the same code. So, I created a base class between them, and transferred the 25 or so "with" methods to it (with the member variables and all.) Like so:
public abstract class Animal {
protected List<String> names = new ArrayList<String>();
public Animal withName(String name) {
names.add(name);
return this;
}
}
public class Bear extends Animal {
protected List<String> foods = new ArrayList<String>();
public Bear withFood(String food) {
foods.add(food);
return this;
}
}
但是,这现在破坏了一切(并且有很多地方在这两个类的设计中使用它).
However, this now breaks everything (And there is a lot of places that use this with design for these two classes).
Bear b = new Bear().withName("jake"); // Breaks
bear b2 = new Bear().withFood("fish"); // Fine
给出的错误:
类型不匹配:无法从 Animal 转换为 Bear
Type mismatch: cannot convert from Animal to Bear
显然,当您返回基类 this 时,它返回的是 Bear 类型,并且不会进行任何类型的自动转换.
Apparently, when you return the base class this, it's returning a Bear type, and does not do any sort of automatic conversion.
我有哪些选择来解决/绕过这个问题?
What are my options to solve/bypass this issue?
推荐答案
您正在寻找 CRTP:
public abstract class Animal<T extends Animal<T>> {
protected List<String> names = new ArrayList<String>();
public T withName(String name) {
names.add(name);
return (T)this;
}
}
这将给出一个不可避免的未检查强制转换警告,因为类型系统无法阻止您编写 class Cat extends Animal
.
This will give an unavoidable unchecked cast warning, since the type system cannot prevent you from writing class Cat extends Animal<Dog> {} class Dog extends Animal<Dog>
.
如果基类中有多个构建器方法,可以通过编写 private T returnThis() { return (T)this; 来隔离警告.}
.
If you have multiple builder methods in the base class, you can isolate the warning by writing private T returnThis() { return (T)this; }
.
相关文章