2017-03-06 14 views
0

たとえば、私はクラスAnimalを持ち、Animalを継承するクラスCat(Bird、Dog、Fish ...)を持っています。今ではAnimalであるクラスPetを宣言したいと思います。既存のAnimalから構築したいと考えています。ネコ。クラスのインスタンスを拡張することは可能ですか?

だから私はこのようなコンストラクタが必要です。

class Pet extends Animal{ 
    private String nickname; 
    private Animal kind; 

    Pet(Animal a, String nickname){ 
     <...>; 
     this.nickname = nickname; 
    } 
} 

EDIT: 私はこのような何かしたい:

Cat cat = new Cat(); 
Animal pet = new Pet(cat, "Foo"); 
if (pet instanceof Pet){ 
    if (pet.kind instanceof Cat){ 
     Pet.sayMeow(); 
    } 
} 

は、それは私がちょうど(保護されています)Animal()が必要であることを意味ですが<でコンストラクタ...>?

+3

自分自身に質問してください。「ペット」は、渡された「動物」と何が関係していますか?あなたは現在それを何もしていないので、この質問は不明です(Animalを渡すあなたの理由は不明です)。 – Tom

+0

@Tomが言ったこと:あなたが達成しようとしていることに関するいくつかの情報がうまくいくでしょう。現在のところ、これはあなたが 'interface'を使うことができるようなものです。 – domsson

+2

あなたが 'Animal'の既存のインスタンスを取得し、**そのインスタンス**を' Pet'に遡って変換したいと言うなら、あなたはそれを行うことはできません。 'Animal'インスタンスから初期化された新しい' Pet'を作成することはできますが、それは分離されます。インスタンスのクラスは、作成時にロックされます。 (インスタンスには異なるインタフェースを持つことができますが、いくつかのコードでは 'Animal'しか知りませんし、他のコードでは' Cat'であることがわかるかもしれませんが、*インスタンス*には特定のクラスが設定されています。 –

答えて

1

あなたの編集後でさえ、あなたの意図は本当に私には分かりません。実行時に、「この猫は以前は迷子でしたが、今は誰かのペットになったばかりです」と言うような方法を探しているようです。

そうですした場合、あなたは非常にシンプルでまっすぐ進むの解決のために行くことができる - 右Animalクラスにこの機能を追加します。

public class Animal { 

    private boolean isPet = false; 
    private String nickname = ""; 

    public Animal() { 
    /*...*/ 
    } 

    public makeStray() { 
    isPet = false; 
    nickname = ""; 
    } 

    public makePet(String nickname) { 
    isPet = true; 
    this.nickname = nickname; 
    } 

    public boolean isPet() { 
    return isPet; 
    } 

    public void makeNoise() { 
    /* Override in child classes */ 
    } 

} 

はあなたの例によると、あなたは、単に行うことができます:

Animal cat = new Cat(); 
cat.makePet("Foo"); 
if (cat.isPet()) { // Apparently, only pet cats ever meow. 
    cat.makeNoise(); // Cats will meow, dogs will bark, ... 
} 

ただし、この方法でコーディングすると、クラスをすばやく膨らませることができます。それは本当にあなたがこれ以外でやる予定のものに依存します。私はこれがクイック 'n'汚いソリューションだと思います。

さらに洗練されたソリューションについては、他の回答を確認してください。

EDIT1:Fildorが正しく方法sayMeow()を持つ、指摘したように、このような良いアイデアではありません。 AnimalmakeNoise()メソッドを追加し、それを子クラスでオーバーライドして、異なる種類のAnimalsの特定の動作を取得してください。ここで実際にAnimalクラスのインスタンスを作成したくない場合は、abstractクラスとmakeNoise()メソッドを作成することもできます。これにより、すべての子クラスがmakeNoise()メソッドを実装する必要があります。または、メソッドがオーバーライドされていない場合は、ミュート・アニマルのデフォルトの動作に問題はありません。

EDIT2This answer関連する質問があなたの状況をより明るくするかもしれません。それはC#についてですが、原則はJavaに変換されます。

+0

私の編集を再編集しましたので、今度は私が望むものが正しく表示されます – Noqrax

+0

本当はありません。あなたは、あなたが働きたいと思うコードをいくつか見せてくれましたが、その背後に*意図はありません。私が正しく読むと、その意図は:「ある動物がペットかどうかを知り、その動物に基づいて行動を起こしたいと思っています。それは上記のコードで可能です。 – domsson

0

"デコレータパターン"としてあなたが何を記述しているかは完全に可能であり、一般的に知られています。

リンクのみの回答が悪いので、後で詳しく説明します。

一方、Wikipediaにはさらに詳しい情報があります:Decorator Pattern


1 Cat cat = new Cat(); 
2 Animal pet = new Pet(cat, "Foo"); 
3 if (pet instanceof Pet){ 
4 if (pet.kind instanceof Cat){ 
5   Pet.sayMeow(); 
6 } 
7 } 

これはinstanceOfを使用する必要があるという欠点があります。通常は、Animalクラスにメソッドがあります。makeNoiseとしましょう。おそらく抽象的です。あなたの動物の実装(CatDog ...)は、それぞれのノイズ( "Bark"、 "Miow" ...)を作るためにそのメソッドをオーバーライドします。

スニペットでは、ペットだけがノイズを発生させることができるようです...それは、それを行うさまざまな方法があるため、少し複雑になります。

デコレータにサウンドを保存させ、そのサウンドを作るためにmakeNoiseをオーバーライドすることができます。これと同じように:

Cat catInstance = new Cat(); 
catInstance.makeNoise(); // Default impl: NOP => "" - no sound. 
Animal pet = new Pet(catInstance, "Mieow"); 
pet.makeNoise(); // => "Mieow" 

このすべてのポイントは次のとおりです。あなたはinstanceofを使用しないようにしたいです。動物が猫の犬、ペットの猫またはペットの犬であるかどうかは気にしません。彼らは正しいことを言われたときに、正しい音を出す。だからあなたは "動物"のコレクションを持っていて、 "makeNoise"にそれらのすべてを教えてもらえます。それぞれがペットであるか、またはAnimalの特定の子供であるかを気にすることなく、それぞれは沈黙しています。

EDIT:私の答えをもう一度読んで、それはデコレータよりもポリシー(戦略パターン)に似ています。 ポリシーは何かが行われたときに変更されますが、装飾者はその機能を追加します。

真のデコレータになるためには、makeNoisePetのインターフェイスにあることを意味します。つまり、あなたは動物のそのメソッドを呼び出すことはできませんでした。

私は「Decorator」から「Strategy」というパターンに変更しました。

上記の例はまだ成り立ちます。デコレータのような実装アプローチを使って、 "デフォルト"の戦略を持ち、 "ペット"戦略を注入します。

もちろん、このすべてをパターンをより厳密に実装するために別の方法で行うこともできます。

最後に、if(x instanceof X) ...は常に「Visitor」-Bellを噛んでいます。

+0

'makeNoise()'がうまくキャッチされました。それに応じて私の答えを編集しました。 – domsson

関連する問題