链接、返回基对象以及与扩展类的类型不匹配

2022-01-24 00:00:00 types polymorphism java

我遇到过这样的课程.它拥有一个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;{} 类 Dog 扩展了 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; }.

相关文章