1

インターフェース:

package sandBox.ps.generics.compositePattern;

import java.util.Collection;

interface AnimalInterface {
    String getID();

    /*
     * getAnimals can be:
     * 1. AnimalInterface
     * 2. Anything that implements/extends AnimalInterface (i.e. AnimalInterface or DogInterface)
     */
    Collection<? extends AnimalInterface> getAnimals();
}

interface DogInterface extends AnimalInterface {
    String getBreed();
}

クラス:

package sandBox.ps.generics.compositePattern;

import java.util.Collection;
import java.util.Collections;

class AnimalClass implements AnimalInterface {
    private final String id;
    private final Collection<? extends AnimalInterface> animals;

    AnimalClass(final String id,
        final Collection<? extends AnimalInterface> animals) {
    this.id = id;
    this.animals = animals;
    }

    @Override
    public String getID() {
    return this.id;
    }

    @Override
    public Collection<? extends AnimalInterface> getAnimals() {
    return this.animals;
    }
}

class DogClass extends AnimalClass implements DogInterface {

    private final String breed;

    DogClass(final String id, final String breed) {
    super(id, Collections.<AnimalInterface> emptyList());
    this.breed = breed;

    }

    @Override
    public String getBreed() {
    return this.breed;
    }

}

クラスのテスト:

package sandBox.ps.generics.compositePattern;

import java.util.ArrayList;
import java.util.Collection;

public class TestClass {
    public void testA() {
    // Dog Collection (Child)
    final DogInterface dog = new DogClass("1", "Poodle");
    final Collection<DogInterface> dogCol = new ArrayList<DogInterface>();
    dogCol.add(dog);

    // Animal Collection of Dogs (Parent)
    final AnimalInterface animal = new AnimalClass("11", dogCol);
    final Collection<AnimalInterface> parent = new ArrayList<AnimalInterface>();
    parent.add(animal);
    // Animal Collection of Animals (Grand-Parent)
    final AnimalInterface grandParent = new AnimalClass("11", parent);

    // Get Dog
    for (final AnimalInterface parents : grandParent.getAnimals()) {
        /* I know the this code would work.
         * My question is, is there anyway to do this without explicit casting
        for (final AnimalInterface child : parents.getAnimals()) {
    if (child instanceof DogInterface) {
        System.out.println(((DogInterface)child).getBreed());
    }
    }
        */

        /*  HERE:   This is the part I am trying to solve.
         *  Do I use extends or super for AnimalInterface
         *  Is there any option such that I don't need to do a casting of some type
         */
        for (final DogInterface child : parents.getAnimals()) {
        System.out.println(child.getBreed());
        }       
    }
    }
}

質問:

  1. テストクラスの最後の行は、動物にアクセスしようとします。
  2. 私が理解しようとしているのは、明示的なキャストを避けるためにとにかくあるのかということです。
  3. これを機能させるextends、super、またはその他の一般的な用語の組み合わせはありますか?
  4. キャスティングが唯一のオプションである場合、それはどこで行われるべきですか?
  5. 私はすでにこれがうまくいくことを知っています:
for (final AnimalInterface child : parents.getAnimals()) {
    if (child instanceof DogInterface) {
       System.out.println(((DogInterface)child).getBreed());
    }
}
4

3 に答える 3

2

あなたはいつでも訪問者を使うことができます:

DogBreedVisitor dogBreedVisitor = new DogBreedVisitor();
for (final AnimalInterface child : parents.getAnimals()) {
    child.visit(dogBreedVisitor);
}

これは非常に単純な実装です。

interface AnimalInterface {
    void visit(AnimalVisitor visitor);
}

interface DogInterface extends AnimalInterface {
    String getBreed();
}

interface AnimalVisitor {
    public void visit(DogInterface dog);
    public void visit(AnimalInterface animal);
}

class DogBreedVisitor implements AnimalVisitor {
    @Override
    public void visit(DogInterface dog) {
        System.out.println(dog.getBreed());
    }
    @Override
    public void visit(AnimalInterface animal) {
       // ignore
    }
}

class DogClass implements DogInterface {
    @Override
    public String getBreed() {
        return "my breed";
    }
    @Override
    public void visit(AnimalVisitor visitor) {
        visitor.visit(this);
    }
}

class AnimalClass implements AnimalInterface {
    @Override
    public void visit(AnimalVisitor visitor) {
        visitor.visit(this);
    }
}
于 2013-02-15T20:15:34.050 に答える
2

残念ながら、スーパークラス参照でサブクラス メソッドを呼び出したい場合は、キャストが必要です。

そうは言っても、私はこれに別の方法で取り組みますが、おそらくプログラムを再構築して、TestClass レベルで扱っている動物の種類を知る必要がないようにします。

たとえば、次の行に沿って何かを行うことができます

for (final AnimalInterface child : parents.getAnimals()) {
    System.out.println(child.getType()); // or something similar

ポイントは、何を返すかを知る責任を実際のクラスに押し付けることができるということです。

「品種」が自然な答えであるクラスは品種を返すことができ、他のクラスは別のものを返すことができます。

この場合、すべての動物にこのメソッド (getType) を持たせたくないかもしれないので、最初に hasType (または何でも) を持つこともできます。

最後に、ある時点で問題の実際のタイプを本当に決定する必要があることがわかった場合は、この決定のみを行う別のクラスにそれをさらにプッシュすることができます.1つのクラスだけがこの知識を持つようにします.

これがすべて理にかなっていることを願っています-それは少しとりとめのない答えです...

于 2013-02-15T20:11:05.647 に答える
0

はい、できます。AnimalInterfaceから取得する動物の種類を示す汎用パラメーターを指定する必要getAnimals()があり、次にAnimalInterface<DogInterface>foranimalおよびAnimalInterface<AnimalInterface<DogInterface>>forを使用する必要がありますgrandParent

完全なコードは次のとおりです。

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;

interface AnimalInterface<A extends AnimalInterface<?>> {
  String getID();

  /*
   * getAnimals can be:
   * 1. AnimalInterface
   * 2. Anything that implements/extends AnimalInterface (i.e. AnimalInterface or DogInterface)
   */
  Collection<A> getAnimals();
}

interface DogInterface extends AnimalInterface<DogInterface> {
  String getBreed();
}

class AnimalClass<A extends AnimalInterface<?>> implements AnimalInterface<A> {
  private final String id;
  private final Collection<A> animals;

  AnimalClass(final String id, final Collection<A> animals) {
    this.id = id;
    this.animals = animals;
  }

  @Override
  public String getID() {
    return this.id;
  }

  @Override
  public Collection<A> getAnimals() {
    return this.animals;
  }
}

class DogClass extends AnimalClass<DogInterface> implements DogInterface {

  private final String breed;

  DogClass(final String id, final String breed) {
    super(id, Collections.<DogInterface> emptyList());
    this.breed = breed;
  }

  @Override
  public String getBreed() {
    return this.breed;
  }

}

class TestClass {
    public void testA() {
    // Dog Collection (Child)
    final DogInterface dog = new DogClass("1", "Poodle");
    final Collection<DogInterface> dogCol = new ArrayList<DogInterface>();
    dogCol.add(dog);

    // Animal Collection of Dogs (Parent)
    final AnimalInterface<DogInterface> animal = new AnimalClass<DogInterface>("11", dogCol);
    final Collection<AnimalInterface<DogInterface>> parent = new ArrayList<AnimalInterface<DogInterface>>();
    parent.add(animal);
    // Animal Collection of Animals (Grand-Parent)
    final AnimalInterface<AnimalInterface<DogInterface>> grandParent = new AnimalClass<AnimalInterface<DogInterface>>("11", parent);

    // Get Dog
    for (final AnimalInterface<DogInterface> parents : grandParent.getAnimals()) {
      for (final DogInterface child : parents.getAnimals()) {
        System.out.println(child.getBreed());
      }
    }
  }
}
于 2013-02-15T20:40:45.483 に答える