繁体   English   中英

是否有比通过反射在继承层次结构中通过工厂方法实例化元素更好的方法?

[英]Is there a better way than using reflection to instantiate elements by a factory method in an inheritance hierarchy?

我建立了一个继承层次结构,其中许多具体类都从抽象超类A继承。 A具有必填属性String a和可选Map b并且对xml模型规范的元素进行建模。 ab中可能的键值对都是aa jaxp.NamedNodeList的一部分。 因此,要设置ab的值,我总是需要遍历列表并检查当前属性是否具有名称“ id”,并分别为a设置值或将键值对添加到b 显然,有人希望将此外包给工厂方法之类。 但是,在抽象超类A实现静态工厂方法显然是不够的,因为通过返回A的新实例,使用工厂方法创建实例时,我需要将实例化转换为具体元素。 因此,我想出了一个使用反射的解决方案,但我确实没有把握,没有比这更简单的方法来解决如此普遍的问题。

还有其他更简单的解决方案吗?

这是我的工厂模式,当将A向下转换为B时导致ClassCastException ,例如SubclassB b = (SubclassB) AbstractSuperClassA.createWith(attributes);

public static AbstractSuperClassA createWith(NamedNodeMap attributes) {
    Map<String, String> attributeMap = new HashMap<>();
    String a= null;
    for (int i = 0; i < attributes.getLength(); i++) {
        if (attributes.item(i).getNodeName().equals("id")) {
            a = attributes.item(i).getNodeValue();
        }
        attributeMap.put(attributes.item(i).getNodeName(), attributes.item(i).getNodeValue());
    }
    if (a == null) {
        // throw RuntimeException
    }
    return new AbstractSuperClassA (identifier, attributeMap);
}

这是通用的反射实现:

public static <T extends AbstractSuperClassA > T init(NamedNodeMap attributes, Class<T> clazz) {
    Map<String, String> attributeMap = new HashMap<>();
    String a= null;
    for (int i = 0; i < attributes.getLength(); i++) {
        if (attributes.item(i).getNodeName().equals("id")) {
            a = attributes.item(i).getNodeValue();
        }
        attributeMap.put(attributes.item(i).getNodeName(), attributes.item(i).getNodeValue());
    }
    if (a== null) {
        // throw RuntimeException
    }
    try {
        Constructor<T> constructor = clazz.getConstructor(String.class);
        T newElement = constructor.newInstance(a);
        newElement.setAttributes(attributeMap);
        return newElement;
    } catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
        log.error(e.getMessage(), e);
    }
    return null;
}

您的init方法似乎需要一种基于单个String值创建给定类的实例的方法。

在这种情况下,您不需要反思。 无需传递Class来实例化和初始化,您可以实现一种“策略模式”形式,其中策略是可变的,并且仅定义如何创建新的,ID初始化的对象。

在Java 8及更高版本中,您可以为此使用功能接口和Lambda:

private <T extends AbstractSuperClassA > T init(NamedNodeMap attributes, Function<String,T> creator) {
  ...
  T newElement = creator.apply(identifier);
  ...
}

然后适当使用它,例如

B someB = init(attrs, B::new);
C someC = init(attrs, id -> {C c = new C(); c.setId(id); return c;});
...

但是,问题是,如何决定应实例化哪个具体类。 无论如何,该逻辑都必须在某处进行编码,因此可能存在更好的方法来连接该逻辑以收集值和初始化新实例。

是否要求实例在构造函数中接收id 还是可以稍后设置?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM