我有两个使用非常相似的方法的对象,除了一行。例如:
public class Cat extends Animal
public class Dog extends Animal
而且它们都使用breed
抽象类中的方法Animal
。一个打电话new Dog()
,另一个new Cat()
。现在我只是将它声明为abstract public void breed();
在 Animal 中,但是有没有一种方法可以概括它,所以我不必让它成为一个被覆盖的抽象方法?
我有两个使用非常相似的方法的对象,除了一行。例如:
public class Cat extends Animal
public class Dog extends Animal
而且它们都使用breed
抽象类中的方法Animal
。一个打电话new Dog()
,另一个new Cat()
。现在我只是将它声明为abstract public void breed();
在 Animal 中,但是有没有一种方法可以概括它,所以我不必让它成为一个被覆盖的抽象方法?
有很多方法可以做到这一点,假设breed
你的意思是“创造我的孩子”。
反射
首先是使用反射。如果你的类有一个无参数构造函数,这就像调用Class.newInstance一样简单:
public Animal breed() {
try {
return (Animal) getClass().newInstance();
} catch (Exception ex) {
// TODO Log me
return null;
}
}
如果在所有子类中都没有无参数构造函数,则必须在所有子类中都有一个统一的构造函数。例如,如果你有Cat(int, String)
and Dog(int, String)
,那么你需要通过它获取构造函数Class.getConstructor
并调用newInstance
它:
return (Animal) getClass().getConstructor(int.class, String.class).newInstance(0, "Unnamed");
int
例如,String
这里可能是年龄和姓名。这就是你如何通过反射来做到这一点的。
提供者
另一种方法是使用这个简单的界面:
public interface Provider<T> {
T create();
}
然后让您的抽象类在其构造函数中获取 this 的实例:
public abstract class Animal {
private final Provider<Animal> animalProvider;
protected Animal( ... , Provider<Animal> animalProvider) {
// ...
this.animalProvider = animalProvider;
}
public Animal breed() {
return animalProvider.create();
}
}
然后您的子类将 a 传递Provider<Animal>
给超类,该超类将创建子类的新实例:
public class Dog extends Animal {
public Dog( ... ) {
super( ... , new DogProvider());
// ...
}
private static class DogProvider implements Provider<Animal> {
public Animal create() {
return new Dog( ... );
}
}
}
对其他子类也这样做。
注意:如果breed
您的意思是“了解我的类型”,那么您应该编辑您的问题以这样说。如果这是您的意思,那么这是一个可行的解决方案:
public abstract class Animal {
protected final Breed breed;
protected Animal( ... , Breed breed) {
// ...
this.breed = breed;
}
public Breed getBreed() {
return breed;
}
}
我建议遵循数据容器方法的get
/set
约定。Java 具有旨在处理这些命名约定的 bean 类,它或多或少是跨许多平台的标准。对于您的子类:
public class Dog extends Animal {
public Dog( ... ) {
super( ... , new Breed( ... ));
// ...
}
}
事实上,是的,你可以。您需要使用反射,因此性能可能有点不确定,但这(未经测试)应该可以工作:
public abstract class Animal{
public Animal breed(){
return getClass().newInstance();
}
//other methods
}
这将返回实际调用类型的新实例,而不是 Animal 的类型(实现它的地方)。
这实际上有点类似于Prototype Pattern。尽管在这种情况下,您正在创建一个新实例,而不是复制现有实例。
编辑
正如@FrankPavageau 在评论中指出的那样,您可以通过使用来获得相同的结果,而不是在构造函数中屏蔽异常
public abstract class Animal{
public Animal breed(){
return getClass().getConstructor().newInstance();
}
//other methods
}
它将包装任何抛出的异常,InvocationTargetException
它更干净,可能更容易调试。感谢@FrankPavageau 的建议。
不,没有。您将必须拥有类似于您所做的事情,如下所示
我想你想在你的抽象类中
public abstract Breed getBreed();
然后在每个子类中都有
public Breed getBreed() {
return new DogBreed();
}
和一只类似的回归猫。
或者
在 Animal 类中有一个受保护的字段,称为品种。然后可以在每个子类中对其进行初始化。这将消除对抽象方法的需要。例如
public abstract class Animal {
Breed breed;
...
}
然后在 Dog have
public class Dog extends Animal {
public Dog() {
breed = new DogBreed();
}
}
并且有类似于猫的东西。
在将品种传递给 Dog/Cat ctor 时可能值得您这样做,这样您就可以创建不同品种的 Dog 对象,而不是将您的模型限制为只有一个品种的 Dog
我不确定 Breed 在您的示例中是否必须正确建模。你真的希望 new Dog() 成为一个品种吗?或者你的意思是类型?在这种情况下,它只是一个动物,返回动物的抽象方法是要走的路。