我構建了一個繼承層次結構,其中一堆具體類繼承自抽象超類A。A具有一個強制屬性 Stringa和一個可選的 Mapb和 xml 模型規范的模型元素。和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;}
1 回答

藍山帝景
TA貢獻1843條經驗 獲得超7個贊
您的init方法似乎需要一種方法來基于單個值創建給定類的實例。String
在這種情況下,您不需要反思。無需傳入Class實例化和初始化,您可以實現一種“策略模式”形式,其中策略是可變的并且僅定義如何創建新的、ID 初始化的對象。
在 Java 8 及更高版本中,您可以為此使用函數式接口和 Lambdas:
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在構造函數中接收?還是可以稍后設置?
添加回答
舉報
0/150
提交
取消