【发布时间】:2015-05-13 13:01:23
【问题描述】:
假设我有以下界面:
interface Mammal {
void marry(Mammal m);
Mammal giveBirthTo();
}
但是,这并不能完全说明我想要什么。
显然,人不能嫁给狗,也不能生猫。那么如何将这些信息嵌入到接口中,以便在实现时可以自动更改输入类型和输出类型?
【问题讨论】:
假设我有以下界面:
interface Mammal {
void marry(Mammal m);
Mammal giveBirthTo();
}
但是,这并不能完全说明我想要什么。
显然,人不能嫁给狗,也不能生猫。那么如何将这些信息嵌入到接口中,以便在实现时可以自动更改输入类型和输出类型?
【问题讨论】:
您可以使用泛型并更改您的设计。
以下内容:
interface Marriable<T extends Mammal> {
void marry(T sweetHalf);
T giveBirthTo();
}
... 其中Mammal 是您的顶级接口或抽象类,Human、Dog、Unicorn 等扩展/实现它。
【讨论】:
Mammal吗?没有理由再添加一个。
Mammal 接口或抽象类来抽象该特定继承链中的顶级动物。 Marriable 接口将定义与您的物种之一结婚的合同。
Marriable 接口。您可以按照我刚刚添加的答案中的建议简单地创建一个递归类型。
HappyToBeSingleHuman 或JustPlainUglyHuman。他们会扩展/实现Mammal,但不会扩展/实现Marriable。
Mammal 接口重构为这样的层次结构。我所说的是你的解决方案添加了一个额外的间接。
您可以使用递归类型变量来生成您的接口:
interface Mammal<T extends Mammal<T>> {
void marry(T m);
T giveBirthTo();
}
这样,Java 编译器可以为您提供一定的验证级别。但是请注意,这种方法仍然容易被滥用。例如:
class Cat implements Mammal<Cat> {
@Override void marry(Cat cat) { ... }
@Override Cat giveBirthTo() { ... }
}
class Dog implements Mammal<Cat> { // implements wrong interface
@Override void marry(Cat cat) { ... }
@Override Cat giveBirthTo() { ... }
}
编译器只能确保您通过同一接口的某些子类型实现Mammal 接口,而不是通过实现它的特定类。后一种类型约束不能用 Java 编程语言表达。
【讨论】:
泛型。试试
private static interface Race {
}
private static class Human implements Race {}
private static class Canine implements Race {}
private static interface Being<R extends Race> {
void marry(Being<R> other);
Being<R> giveBirthTo();
}
private void tryMe() {
Being<Human> aHuman = new Being<Human>() {
@Override
public void marry(Being<Human> other) {
}
@Override
public Being<Human> giveBirthTo() {
return null;
}
};
Being<Canine> aCanine = new Being<Canine>() {
@Override
public void marry(Being<Canine> other) {
}
@Override
public Being<Canine> giveBirthTo() {
return null;
}
};
aHuman.marry(aCanine); // not possible
}
【讨论】: