2012-01-28 23 views
3

私は、Javaが多重継承をサポートしていないことに気付いています。しかし、もし私が動物の王国のようなクラスシステムを設計しなければならないならば。 2つの異なる動物のハイブリッドである動物を表現するには?例えば、ミュール(ロバまたは馬?)、ライガー(ライオンまたはタイガー)。 LigerクラスとTigerクラスの両方を継承してLigerクラスを作成する方法は? TigerとLionをインターフェイスとして使用せずに行う方法はありますか?インタフェースを作成できない場合はどうすればよいですか?クラス階層の設計 - Javaでの多重継承

答えて

8

継承は、この場合に使用する権利ツールではありません。あなたは、ライガーはではなく、虎であり、どちらもライオンではありません。 は両方ともの特性を持っていますが、です。

あなたは動物園に行くとケージは「タイガー」と言うと言います。この奇妙な巨大な猫を見て、あなたが確かに虎として認識していないことを確かめてください。 It's coolですが、トラはありません。あなたはまたそれがライオンだとは思わない。いずれにしてもsubstitutableではありません。

だから、それは完全に、または部分的にLion、右1にTigerデリゲートその行動、または「上書き」彼らの行動を構成する必要があります。

UPDATE:

あなたは本当に、多重継承のいくつかの種類をしたい場合は今、何をしたいあなたは、両方のHybridFelineからLigerを導出したい場合は?可能であればScala traitsを見てください。これをJavaで実装するには、デザイン内の各概念のインターフェイスとクラスを継承する必要があります。アイデアのためにhereを見てください。

+1

+1。 IMO、これはこれまでのところ最高の答えです。 –

+1

素敵な説明!このようなシナリオをどのように処理するかは、はるかに明確になっています。私は委任と構成コンセプトにはあまり慣れていませんが、間違いなく掘り下げて学びます。ご協力いただきありがとうございます。 – Periastron

0

あなたが言及したように、それは不可能です。また、それは悪いデザインの兆候でもありえます(たとえ可能であってもあいまいさをもたらすかもしれません)。だから、それを避けてデザインを考え直さなければならないかもしれません。

+0

あいまいさをもたらすかどうかは、サブクラス化されているものによって決まります。 –

+0

IMHO、Ligerの場合、あいまいさをもたらす可能性が非常に高いです。 –

+1

確かに、それは常にサブクラス化されているものとクラスの振る舞いに依存します。私の指摘は、それが悪い設計の兆候であるということは、私が信頼性をもって主張できるとは考えていない徹底的な一般化だということでした。 –

6

の場合は、の場合は、1つのオブジェクトで両方を識別できるようにする必要があります。あなたは動物の行動が優先されますかを決定する必要があるだろう、

は、あなたは、多くの場合、合成クラスに行動を委任することができますが、ライガーの場合は(それはかなり私のお気に入りのサブクラスです)。ライガーは、どちらか一方の直接の子孫でも、どちらでもないかもしれません。

のJavaのみ複数の "APIの継承"(インターフェイス)、しない実装が可能になります。

0

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は、複数のクラスの継承をサポートしていないので、これはワーク・ない「ライオンが延び、タイガー」クラス宣言の一部が違法です。 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の設計は、「何かがあいまいで安全でない、未定義である、あるいはタイプまたは解析の競合を引き起こす可能性がある場合は、プログラマがコードを書くことができます

0

私はあなたがこれを行うが、反射が仕事ができる推薦ませています。もちろん、 "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 
    } 
} 
+0

それはちょうど醜い、信頼性のない委任の方法です。 –

+0

ああそうです...それはうまくいくでしょうが、それはうまくいくでしょう。 –