【发布时间】:2012-01-28 00:03:42
【问题描述】:
我知道 Java 不支持多重继承。但是如果我必须为动物王国设计一个类系统。如何表示由两种不同动物杂交而成的动物?例如,骡子(驴或马?),狮虎(狮子或老虎)。如何继承 Lion 和 Tiger 类来创建 Liger 类? 有没有办法在不将 Tiger 和 Lion 作为接口的情况下做到这一点?如果不能做接口怎么办?
【问题讨论】:
我知道 Java 不支持多重继承。但是如果我必须为动物王国设计一个类系统。如何表示由两种不同动物杂交而成的动物?例如,骡子(驴或马?),狮虎(狮子或老虎)。如何继承 Lion 和 Tiger 类来创建 Liger 类? 有没有办法在不将 Tiger 和 Lion 作为接口的情况下做到这一点?如果不能做接口怎么办?
【问题讨论】:
在这种情况下,继承不是正确的工具。你看,狮虎不是老虎,也不是狮子。它具有两者的特征,但不是。
假设你去动物园,笼子里写着“老虎”。你往里窥视,看到这只奇怪的巨猫,你肯定认不出它是老虎。 It's cool,但不是老虎。你也不认为它是狮子。也不是substitutable。
因此,它应该组合Lion 和Tiger 并将其行为委派到正确的行为,或完全或部分“覆盖”它们的行为。
更新:
现在,如果你真的想要某种多重继承,比如你想从Hybrid 和Feline 派生Liger,该怎么办?看看Scala traits 的可能性。要在 Java 中实现它,您需要一个接口和一个类用于设计中要乘以“继承”的每个概念。看看here 的想法。
【讨论】:
它们总是需要是接口iff您希望单个对象可以识别为两者。
您通常可以将行为委托给复合类,但对于狮虎(它几乎是我最喜欢的子类),您需要决定哪种动物的行为具有优先权。狮虎可能是其中一个的直系后代,也可能不是。
Java 只允许多个“API 继承”(接口),不允许实现。
【讨论】:
Java 不支持多类继承。考虑一下“狮子”和“老虎”可能具有的共同功能。 Java 不想解决“函数冲突”问题:
class Lion{
public String call(){
return "ROAR";
}
}
class Tiger{
public String call(){
return "growl";
}
}
class Liger extends Lion, Tiger{
}
public static void main(String[] args){
System.out.println(new Liger().call());
}
应该打印什么?
Java 不支持多类继承,因此这不起作用——类声明的“扩展 Lion、Tiger”部分是非法的。 Java 支持接口的消歧机制,但这并没有扩展到类。
最好的办法是将每个动物类转换为接口,然后将代码转换为这些接口的实现。 Liger 可以按如下方式实现:
interface Liger extends Lion, Tiger { }
class LigerImpl implements Liger{
private Lion mom;
private Tiger dad;
public LigerImpl(){
mom = new LionImpl();
dad = new TigerImpl();
}
public String call(){
if(math.random() > 0.5){
return mom.call();
} else {
return dad.call();
}
}
这种方法需要对每个底层实现进行显式委托;绝对没有“免费”发生。不过,Java 不会让您更接近。 Java 的设计几乎可以归结为“如果有任何含糊、不安全、未定义或可能导致类型或解析冲突的东西,请让程序员编写更多代码。”
【讨论】:
正如你所提到的,这是不可能的。此外,这也可能是设计不佳的标志(因为即使可能,它也可能带来歧义)。因此,您可能不得不尝试避免它并重新考虑您的设计。
【讨论】:
我不建议您这样做,但反思可能会起作用。当然,使用“instanceof”永远不会奏效......
public class Lion {
public void roar() {
System.out.println("Lion is roaring");
}
public void eat(String what) {
System.out.println("Lion is eating " + what);
}
}
public class Tiger {
public void purr() {
System.out.println("Tiger is purring");
}
public void eat(String what) {
System.out.println("Tiger is eating " + what);
}
}
import java.lang.reflect.Method;
import java.util.ArrayList;
public class Liger {
public static void main(String[] args) {
Liger liger = new Liger();
liger.purr();
liger.roar();
liger.eat("food");
//Result
//Tiger is purring
//Lion is roaring
//Tiger is eating food
//Lion is eating food
}
private ArrayList<Object> _extends = new ArrayList<Object>();
public Liger() {
_extends.add(new Tiger());
_extends.add(new Lion());
}
private void invoke(String methodName, Object... args) {
for ( Object obj : _extends ) {
Class cls = obj.getClass();
Method[] methods = cls.getMethods();
for ( Method m : methods ) {
if ( m.getName().equals(methodName) ) {
try {
m.invoke(obj, args);
}
catch ( Exception ex ) {
//handle me
}
continue;
}
}
}
}
public void purr() {
invoke("purr"); //Tiger only
}
public void roar() {
invoke("roar"); // Lion only
}
public void eat(String what) {
invoke("eat", what); //Both
}
}
【讨论】: