java - 有没有比使用反射通过继承层次结构中的工厂方法实例化元素更好的方法?
问题描述
我构建了一个继承层次结构,其中一堆具体类继承自一个抽象超类A
。A
具有 XML 模型规范的必需属性 Stringa
和可选的 Mapb
和模型元素。两者a
和可能的键值对b
都是 jaxp.NamedNodeList 的一部分。因此,要设置 和 的值a
,b
我总是需要遍历列表并检查当前属性是否具有名称“id”,并分别设置值a
或将键值对添加到b
. 显然,有人想将其外包给工厂方法等。但是,在抽象超类中实现静态工厂方法A
显然是不够的,因为通过返回 A 的新实例,我需要在使用工厂方法创建具体元素时将实例化向下转换为具体元素。所以我想出了一个使用反射的解决方案,但我真的很不安全,没有更简单的方法可以解决一个看起来如此普遍的问题。
有没有更简单的解决方案?
这是我的工厂模式,这导致了将ClassCastException
A 向下转换为 B 时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
在构造函数中接收?还是可以稍后设置?
推荐阅读
- windows - 为什么说 Windows NT 内核是混合模型?
- powerbuilder - 哪个更快 - Powerbuilder 中的数据存储或结构?
- java - 具有课程对象和先决条件的Java递归
- python - Flask/HTML 问题:来自 html 中输入文本框的请求在哪里到达 Flask 中的 app.route?
- python - Python:使用导入的表(.txt 文件)并编辑要省略的某些值
- python - 熊猫:计算日期时间戳之间的先前记录之间的运行差异
- ios - 将自定义单元格插入 TableView
- jquery - StickyBits 不粘
- c++ - 尝试解除分配二叉搜索树时出错(仅适用于原始数据类型)
- python - 我有一个包含字典的列表。如何附加到特定键的值?