当用户传入其他类时,如何允许类构造其他类?

时间:2010-10-11 02:27:56

标签: java oop

假设你有一个班级人口和人口是一个内部的个人名单。用户希望将未构造的Individual子类传递给Population,并让Population完成构造这些子类的工作,无论传递什么子类。

  public class Population{

    private List<Individual> indiList = new ArrayList(25);


    /*I know this won't work for multiple reasons, but shows the idea*/
    public void addIndividualsOfType(Individual individual){

    for (ListIterator it = indiList.listIterator(); it.hasNext(); ){
      it.next()
      it.add(individual.construct(param1, param2, param3);  
    }
  }

}

  public abstract class Individual{
  SomeType param1;
  ...

  public Individual(SomeType param1, SomeType param2, SomeType param3){
    this.param1 = param1;
    ...
  }
}

  public class HappyIndividual extends Individual{
   ...
  }

  public class SadIndividual extends Individual{
   ...
  }

我希望能够拨打population.addIndividualsOfType(HappyIndividual)

这样的电话

显然,此代码不会出于多种原因(例如传递未实例化的类)。我只是想说明我想做什么的想法,这不是上述代码为什么不起作用的问题。我知道它不起作用,这就是为什么我无法弄清楚如何做这样的事情。

我整天都在忙着使用Builders和Static Factory Methods。问题是我们在这里讨论子类。子类与静态不兼容。如果我给个人一个静态工厂方法,那么我最终创建个人,而不是HappyIndi​​viduals。 Builder也会出现类似的问题。我也希望保持这不过分复杂。

我觉得这应该很容易,但我遇到了麻烦。感谢。

3 个答案:

答案 0 :(得分:1)

  

我希望能够像人口一样打电话.addIndividualsOfType(HappyIndi​​vidual)

当你要求这样做时,你非常接近。您可以改为传递HappyIndividual.class,它是表示HappyIndividual类的类对象。此对象本身的类型为Class,表示运行时的类。

您的方法将如下所示:

public void addIndividualsOfType(Class<? extends Invididual> clazz) {
    for (ListIterator it = indiList.listIterator(); it.hasNext(); ){
      it.next();
      it.add(clazz.newInstance());
    }
}

newInstance的调用假定您的类具有不带参数的默认构造函数。否则,您需要使用getConstructor方法获取特定的构造函数,然后使用正确的参数在该构造函数上调用newInstance

答案 1 :(得分:1)

基本上有两种方法可以做到这一点:

您可以继续关注当前路径并使用反射构建类:

public void addIndividualsOfType(Class<? extends Individual> clazz){
    for (ListIterator it = indiList.listIterator(); it.hasNext(); ){
        it.next()
        it.add(clazz.newInstance());  // using no-args constructor
    }
}

并使用带有参数的构造函数,用这样的代码替换it.add(clazz.newInstance())

    Constructor<? extends Individual> cons = clazz.getConstructor(
        param1.getClass(), param2.getClass(), param3.getClass());
    it.add(cons.newInstance(param1, param2, param3));

(我已经省略了异常处理......但是你得到了照片。)

但是,一个更好的方法是重构代码,以便传入工厂对象而不是Class对象。例如:

public interface IndividualFactory {
    public Individual create(T1 p1, T2 p2, T3 p3);
}

public static final IndividualFactory TALL_FACTORY = new IndividualFactory() {
    public Individual create(T1 p1, T2 p2, T3 p3) {
        return new TallIndividual(p1, p2, p3);
    }
};

public void addIndividualsOfType(IndividualFactory factory){
    for (ListIterator it = indiList.listIterator(); it.hasNext(); ){
        it.next()
        it.add(factory.create(param1, param2, param3);
    }
}

请注意,可以对基于工厂的解决方案进行静态类型检查。相比之下,反射版本必须处理许多与类型相关的运行时异常。

答案 2 :(得分:0)

传递相关课程(例如HappyPerson.class)并通过调用Class.getConstructor(arg...)获取构造函数,然后实例化实例。