根据另一个类创建一个类的实例

时间:2012-09-20 16:32:06

标签: java class inheritance instance

在Java中,我有一个类X和一个接口Y,然后是一组类A1 ..然后扩展X并实现Y。 然后,我为每个类A1..An(即A1'..An')创建一个包装器/适配器。

现在,在客户端类C中,我收到了接口YArrayList < Y >)的实例列表。

在这个地方,对于列表中的每个实例,我想根据事实Ax'的实例创建一个类A1'..An'的新实例(来自Y)名单。让A1制作A1'

我怀疑的是,如果没有if .. else if ...和(实例)构造,我怎么能实现这一目标。我能以某种方式在这里使用继承吗?

我正在检查一些设计模式,但我找不到解决方案如何根据哪个实例是另一个类来创建类。

任何帮助和建议将不胜感激。谢谢。

6 个答案:

答案 0 :(得分:2)

for(Y y : ArrayList < Y >)  
{  
   y.getClass().newInstance();  
}  

如果我理解你的问题......

编辑

abstract class X implements Y 
{
    Y getInstance();
}

class A1 extends X
{
    void someMethod()
    {
        getInstance(); // return instance of A1_
    }
}

class A1_ extends A1
{
    Y getInstance()
    {
        return new A1_();
    }
}    

<强> EDIT2

如果你想在孩子身上得到父亲的实例,你可以做

this.getClass().getSuperclass().newInstance();

答案 1 :(得分:1)

您可以使用Class.forName()方法创建包装器。类A1..AN和包装类名称之间的映射可以存储在硬编码,属性或XML文件中,或者如果要使用放在A1 ... AN类上的注释。

答案 2 :(得分:1)

for(Y y : ArrayList < Y >)  
{  
  Class<?> clazz = Class.forName(y.getClass().getName()+"Adapter");
  YAdapter ya = (YAdapter)clazz.newInstance();
}

混合两个答案。

答案 3 :(得分:1)

创建HashMap<Class<Y>, Class<?>>。对于每个An和A'n,创建关系:map.put(An.class, A'n.class)

然后,对于ArrayList中的每个obj,获取A'类:Class aa=map.get(obj.getClass())。然后创建类aa的实例,或者使用aa.newInstance()(然后通过setter传递obj),或者使用使用反射的构造函数(并传递obj作为参数)。

答案 4 :(得分:1)

首先,您需要一种方法将适配器(A' 1 ... A' n )与具体实例相关联(A 1 .. n )。最好使用Map<Class<?>, Constructor<?>>完成此操作。一个好方法是围绕它编写一个注册表:

public class AdapterRegistry {
    private static final Map<Class<?>, Constructor<?>> adapterMap =
            new HashMap<Class<?>, Constructor<?>>();

    public static void register(Class<?> interfaceClass, Class<?> concreteClass, Class<?> adapterClass) 
            throws NoSuchMethodException {
        // Check for the constructor
        Constructor<?> constructor = adapterClass.getConstructor(interfaceClass);
        adapterMap.put(concreteClass, constructor);
    }

    public static <T, V extends T> T wrap(V v) {
        Class<?> concreteClass = v.getClass();
        try {
            Constructor<?> constructor = adapterMap.get(concreteClass);
            if (constructor != null) {
                return (T) constructor.newInstance(v);
            }
        } catch (Exception ex) {
            // TODO Log me
        }
        return null;
    }
}

然后,这只是创建适配器的问题:

public class Adapter implements Y {
    private Y innerY;

    public Adapter(Y innerY) {
        this.innerY = innerY;
    }

    // Implement Y
}

注册您的适配器:

AdapterRegistry.register(Y.class, A1.class, Adapter1.class);
AdapterRegistry.register(Y.class, A2.class, Adapter1.class);
AdapterRegistry.register(Y.class, A3.class, Adapter2.class);
// ...
AdapterRegistry.register(An.class, AdapterM.class);

如果您愿意,请注意如何为同一个类注册多个适配器。这样,如果具体类的子集将以相同的方式处理,您只需为所有这些都注册相同的适配器。

接下来,获取包装器:

for (Y y : yList) {
    Y adapter = AdapterRegistry.wrap(y);
    // Do something with the adapter
}

这有一定的限制:

  • 每个适配器中都必须有一个构造函数,它通过接口获取具体对象
  • 接口必须包含您要更改的方法(如果使用Y作为innerY的类型,您可以更改此设置,以便您可以访问非接口方法,但然后你必须做铸造)。

由于使用了泛型,您也可以在程序的其他部分使用AdapterRegistry

如果代码有任何问题,请告诉我,你无法弄明白。

答案 5 :(得分:1)

在这种情况下避免if / else-chains的一个标准解决方案是使类实现一些包含一个方法的接口,该方法使对象知道自己要做什么 - 即按照你的建议使用继承。

具体的类知道他们自己的具体类型,如何复制自己等等,但是你不知道在循环中 - 所以将创建新的具体类的责任转移到具体的类本身是有意义的

我要做的是向创建新实例的Y接口添加新方法。 例如,如果您只想在列表中获取实例的副本,则可以添加&#34;副本&#34;工厂方法到Y

public interface Y {
    ...
    public Y copy();
    ...
}

Y的每个实现都必须实现复制方法。它知道如何复制自己。示例:

public class MyClass implements Y {
    ...
    public MyClass copy() {
        return new MyClass(...);
    }
    ...
}

因此,在迭代列表时创建新实例然后就变成这样:

List<Y> ys = ...get list from somewhere...;
for (Y y : ys) {
    Y copy = y.copy();
    ...
}

请注意,此方法不需要反射或其他黑客攻击。

另请注意,循环不必了解具体类 - 它只需要知道接口Y。特定于具体类的所有代码都保存在具体类本身中。这使得使用它们的代码更简单(避免使用instanceof + if / else链)。

您可以使用一些参数来创建更高级的方法,而不是复制方法。如果对象不必复制自己,但必须根据某些输入以某种特殊方式创建自己的新实例,这可能很有用。

(注意:这种复制方法可能会提醒你&#34; clone&#34;,但由于Java中的克隆已经完全破解,这通常是一种更好的方法)

注意:我假设Ai'包装和Ai都延伸Y

注意:如果您无法对Y进行更改,但可以更改适配器类,则可以创建一个扩展Y'的新接口Y以及适配器-classes实现,并使用List<Y'>而不是List<Y>来迭代循环中的那些。