4

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

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

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

if我的疑问是,如果没有……else if和(实例)构造,我怎么能做到这一点。我可以在这里以某种方式使用继承吗?

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

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

4

6 回答 6

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_();
    }
}    

编辑2

如果你想在孩子中获取父母的实例,你可以这样做

this.getClass().getSuperclass().newInstance();
于 2012-09-20T16:36:42.667 回答
1

首先,您需要一种将适配器 (A' 1 .. A' n ) 与具体实例 (A 1 .. A 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由于使用了泛型,因此您也可以在程序的其他部分使用您的。

让我知道代码是否有任何问题,而您无法弄清楚。

于 2012-09-20T17:08:21.383 回答
1
for(Y y : ArrayList < Y >)  
{  
  Class<?> clazz = Class.forName(y.getClass().getName()+"Adapter");
  YAdapter ya = (YAdapter)clazz.newInstance();
}

混合两个答案。

于 2012-09-20T16:42:40.013 回答
1

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

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

于 2012-09-20T16:45:25.843 回答
1

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

于 2012-09-20T16:38:14.643 回答
1

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

具体类知道它们自己的具体类型、如何复制自己等,但您在循环中不知道这些 - 因此将创建新具体类的责任转移到具体类本身是有意义的。

我要做的是向Y创建新实例的接口添加一个新方法。例如,如果您只想获取列表中实例的副本,则可以将“复制”工厂方法添加到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 链)。

除了复制方法,您当然还可以创建更高级的方法,也许可以使用一些参数。如果对象不仅必须复制自己,而且必须根据某些输入以某种特殊方式创建自己的新实例,这可能会很有用。

(注意:这种复制方法可能会让你想起“克隆”,但由于 Java 中的克隆很糟糕,这通常是一种更好的方法)

注意:我假设Ai'wrappers 和Aiextends Y

注意:如果您不能对 进行更改Y,但可以更改适配器类,则可以创建一个新接口Y',该接口扩展Y并由适配器类实现,并使用 aList<Y'>代替List<Y>您在循环中迭代的接口。

于 2016-03-26T14:17:37.977 回答