2016-02-20 16 views
6

Java - クラスのすべてのサブクラスを単一のクラスで拡張することは可能ですか?Java - クラスのすべてのサブクラスを単一のクラスで拡張することは可能ですか?

例をあげて説明しますが、実際のコードはかなり複雑です。私は独自のクラス階層を持つAnimalクラスを持っています。 TestarrosaとViperの2つのサブクラスがあるとしましょう。

public class Car { 

    public abstract String getManufacturer(); 
} 

public class Testarossa extends Car{ 

    public String getManufacturer(){ 
     return "Ferrari"; 
    } 
} 

public class Viper extends Car{ 

    public String getManufacturer(){ 
     return "Dodge"; 
    } 
} 

すべてのCarサブクラスをRegisteredCarサブクラスで拡張したいと考えています。

public class RegisteredCar extends Car { 

    private String plateNumber; 

    public RegisteredCar (String plateNumber){ 
     this.plateNumber=plateNumber; 
    } 

    public String getPlateNumber() { 
     return plateNumber; 
    } 
} 

ある時点で、特定のサブクラスの新しいRegisteredCarを作成できるはずです。

RegisteredCar c = new RegisteredCar<Viper>("B-3956-AC"); 

のようなものとB-3956-ACを得るために、 "ダッジ" とc.getPlateNumberを()得ることがc.getManufacturer()を呼び出します。明らかに、私はまだ作成する必要がありますCar c = new Viper();

これは例です。登録されていない場合、null値を持つCarの属性を持つことは、私が必要とするものでは不十分です。

+3

*「のは、それは2つのサブクラスがあるとしましょう:ゴリラとオオカミの」* ..私はあなたがあなたの 'Car'例に固執する必要がありますね;)。 – Tom

+0

ですが、できません。 –

+0

ViperとTestarossaの基本クラスをRegisteredCarに変更することはできませんか? – sfThomas

答えて

4

は、なしのthats本当に可能とあなたの例ではないが、あなたがCarインスタンスをラップするために別のクラスを使用することができます継承する代わりに、あなたのモデル

を変更することで解決することができます。
私は(RegisteredCarCarを拡張有するあまりにも動作するはずですが)Carインターフェースを作成し、その後、以下の擬似コードのようなものを試みる:

class RegisteredCar<T extends Car> implements Car { 
    private final T car 

    RegisteredCar(T car) { 
    this.car = car; 
    } 

    ... methods for RegisteredCar 
    ... methods from Car delegating to `this.car` 
} 

やや悪いコードを言い訳してください、私はIDEのオープンを持っていません私はいつもIDEを使わずにジェネリックを駄目です。

もう一つの考えられる解決策は、最近の流行がどのようにファッションにあるのかわからないが、あなたが描いていることがクロスカットの問題になる可能性があるということです。

最終選択肢が他の回答で説明したようにジェネリッククラスのアプローチで

+1

私がブシャンに言ったように、それは完璧ではありません。これは私が今までに見つけた最良の解決策です。残念ながら、それはJavaでなければなりません:( –

+0

ありがとう:)その完璧ではありませんが、Javaに制限されている場合は、言語の短いものに対処する必要があります。汎用言語は完璧ではありません。しかし、JVMはJava相互運用性を備えたいくつかの偉大な言語を持っていますが、 "リーダー"に適切なときに他の言語を少し混ぜるように説得することは不可能です。がんばろう。 – Gavin

2

Javaでは、1つ以上のクラスを拡張することは禁止されています。 たとえば、クラスからクラスへのチェーンを構築することができます。 Javaでの多重継承の問題を解決するには→インタフェースを使用する

+1

これは多重継承の問題ではありません。私は複数のクラスから継承する1つのクラスを作成しようとしていません。これは一般的な継承の問題です。あなたはどのクラスを拡張しているのかわかりません。 –

10

要するに、それは不可能ではありません。残念ながら、あなたのオブジェクトモデルを変更する必要があります。

例えば、何Registrationクラスを持っていることについて、このよう:あなたのCarモデルを維持しながら、あなたは、単一のクラスに登録に関する情報を抽出することができます

public interface Registration<C extends Car> { 
    C getCar(); 

    String getPlateNumber(); 
} 

この方法です。

そのあとのようなヘルパーメソッド行うことができます:いいえ、それはC++のようではありません

Registration<Viper> registeredViper = createRegistration(new Viper(), "B-3956-AC"); 
+0

ああ!私の答えとほぼ同じです。私は 'Car'インターフェースを実装するようにして、' Car'が使われているところでそれを使うことができます。実装されたメソッドを 'Car'インスタンスに代入するだけです。答えをアップしました。 – Gavin

1

を。 Javaでは多重継承はできません。ただし、複数のインターフェイスを実装することはできます。

+1

これは多重継承の問題ではありません。私は複数のクラスから継承する1つのクラスを作成しようとしていません。これは一般的な継承の問題です。あなたはどのクラスを拡張しているのかわかりません。 –

0

これを継承で達成することはできません。 あなたの最良のオプションは、その後、意図したタイプの車を保持している一般的なインスタンス変数持つ、RegisteredCarタイプは、一般的な作っている:これで

public class RegisteredCar<T extends Car> { 
    private String plateNumber; 
    private T car; 

    public T getCar() { 
     return this.car; 
    } 
    public T setCar(T car) { 
     this.car = car; 
    } 
    public RegisteredCar (String plateNumber){ 
     this.plateNumber=plateNumber; 
    } 
    public String getPlateNumber() { 
     return plateNumber; 
    } 
} 

を、あなたはRegisteredCarに、サブクラスだ任意の型のオブジェクトを渡すことができるようになります車の

気づいているとおり、このクラスの一部はextends Carであり、車のサブクラスである必要はありません。

2

可能な限り継承を避ける必要があります。抽象(インタフェース)を使用してコードをエレガントにし、メンテナンス可能を使用します。ただgoogle なぜ拡張は悪いです。他の人が言ったように

public interface Car{ 
     String getManufacturer(); 
    } 

    public interface Registerable{ 
     boolean isRegistered(); 
     void register(String plateNumber); 
     void getPlateNumber(); 
    } 

    public class Viper implements Car, Registerable 
    { 
     //all methods 
    } 
+1

クラスの継承はまったく悪いことではありません。あなたのソリューションでは、プログラマはすべてのサブクラスで共通のメソッドを実装する必要があります。どのように維持することができますか? –

+1

共通の機能が必要な場合は、その機能を実装して抽象化し、その抽象化を必要とするすべてのクラスに作成することができます。この方法では、実装への依存を避けることができます。実装を変更することができます。実装が完全に隠されているため、誰も気づかないでしょう。これは、継承上の_合成と呼ばれます。スーパークラスの小さな変更は、すべてのサブクラスを破棄したり、微妙なバグを伴う可能性があります。抽象化の構成と依存性は、そのような問題を回避するのに役立ちます。 – callOfCode

+0

それは同じメソッドを何度も繰り返し実装する必要はありません。つまり、共通の機能を1つの場所に実装し、それを抽象化し、その抽象化を必要とするすべてのクラスに渡します。 – callOfCode

1

「にミックス」拡張機能、設定上の特徴、プロトコルまたはいくつかの他のタイプのために可能にする言語を使用するかもしれない、あなたのことができるようになりません。 を使用して、Carオブジェクトを渡す必要があります。例えばいくつかの請求書を生成する必要があるとします。それはタイプの車でないと、あなたがRegisteredCarを使用することはできません。この方法では

Invoice getInvoice(Car c); 

。 Carを必要とするAPIはすべてRegisteredCarには適用されません。場合によっては、プレート番号とカーが必要な場合があります。そこでは、プレート番号とカーのマッピングを維持する必要があります。私は、すべての車が通過した車のオブジェクトへの呼び出し

public class RegisteredCar extends Car{ 

    public RegisteredCar(Car c, String plateNumber){ 

    }   
    @Override 
    String getColor(){ 
     c.getColor(); 
    } 
} 
+1

私は最初の部分に同意します。 最後に2つの異なるインスタンスを保持し、新しいCar()と新しいRegisteredCar()を呼び出す必要があるので完璧ではありませんが、これはJavaの欠点を解決する良い方法です。クラスのパラメータ化(Gavinの解法)は、特定のサブクラスのパラメータを必要とするメソッドに対しては少し進んでいます。 compareTo(Viper a) –

0

は、理由はあなたが単に既存の基底クラスに新しい機能を追加することができなかったことを、実際の授業では、あり飾るパターンとデリゲートに基づいて、次のアプローチを示唆しています?

public abstract class Car 
{ 
    public abstract String getManufacturer() ; 

    protected String plate_number = null ; 

    public String getPlateNumber() 
    { return this.plate_number ; } 

    public boolean isRegistered() 
    { return (this.plate_number != null) ; } 
} 
関連する問題