在Java中,我有一个类X
和一个接口Y
,然后是一组类A1
..然后扩展X
并实现Y
。
然后,我为每个类A1..An
(即A1'..An'
)创建一个包装器/适配器。
现在,在客户端类C
中,我收到了接口Y
(ArrayList < Y >
)的实例列表。
在这个地方,对于列表中的每个实例,我想根据事实Ax'
的实例创建一个类A1'..An'
的新实例(来自Y
)名单。让A1
制作A1'
等
我怀疑的是,如果没有if
.. else if
...和(实例)构造,我怎么能实现这一目标。我能以某种方式在这里使用继承吗?
我正在检查一些设计模式,但我找不到解决方案如何根据哪个实例是另一个类来创建类。
任何帮助和建议将不胜感激。谢谢。
答案 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>
来迭代循环中的那些。