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. 是否有任何扩展,超级或其他通用术语的组合可以使这项工作?
  4. 如果铸造是唯一的选择,应该在哪里完成?
  5. 我已经知道这会起作用:
for (final AnimalInterface child : parents.getAnimals()) {
    if (child instanceof DogInterface) {
       System.out.println(((DogInterface)child).getBreed());
    }
}
4

3 回答 3

2

恐怕如果您想在超类引用上调用子类方法,那么确实需要进行强制转换。

也就是说,我会以不同的方式解决这个问题,但可能会重新设计你的程序,这样就没有必要在 TestClass 级别知道你正在处理什么样的动物。

例如,您可以按照以下方式做一些事情

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

关键是您可以将知道要返回什么的责任推给实际的课程。

“品种”是自然答案的类可以返回品种,对于其他人来说,它可以返回其他东西。

在这种情况下,您可能不希望每只动物都拥有此方法(getType),因此您也可以先拥有一个 hasType(或其他)。

最后,如果您发现在某些时候确实需要确定有问题的实际类型,您可以进一步将其推送到另一个只进行此确定的班级,留下这样只有一个班级有这种知识。

我希望这一切都有意义 - 这是一个有点漫不经心的答案......

于 2013-02-15T20:11:05.647 回答
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 回答
0

是的,你可以做到。你需要给AnimalInterface一个通用参数,告诉你你从什么类型的动物身上得到getAnimals(),然后你需要使用AnimalInterface<DogInterface>foranimalAnimalInterface<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 回答