我正在尝试实现构建器模式以生成Apache XmlBeans对象。
我为所有类生成了构建器,它们继承自:
public abstract class Builder<T extends XmlObject> {
protected T xmlObject;
@SuppressWarnings("unchecked")
public T build() {
return (T) xmlObject.copy();
}
}
然后我创建了几个这样的构建器(Time2Save继承自XmlObject):
public class Time2SaveBuilder extends Builder<Time2Save> {
public Time2SaveBuilder(int amount, String unit) {
xmlObject = Time2Save.Factory.newInstance();
xmlObject.setUnit(unit);
xmlObject.setValue(amount);
}
}
它完美无缺。但我遇到的问题是,我不喜欢在每个构建器中实例化xmlObject的重复,如果可能的话,我宁愿在抽象的构建器类中执行它。所以我尝试将此构造函数添加到Builder类中:
@SuppressWarnings("unchecked")
public Builder() {
xmlObject = (T) T.Factory.newInstance();
}
离开这样的实现:
public class Time2SaveBuilder extends Builder<Time2Save> {
public Time2SaveBuilder(int amount, String unit) {
xmlObject.setUnit(unit);
xmlObject.setValue(amount);
}
}
问题是我收到以下错误:
Exception in thread "main" java.lang.ClassCastException:
org.apache.xmlbeans.impl.values.XmlAnyTypeImpl cannot be cast to
a.b.c.d.Time2SaveDocument$Time2Save
我认为XmlAnyTypeImpl
是调用静态XmlObject.Factory
而不是继承类(在本例中为Time2Save
)的结果。我想知道为什么会发生这种情况(因为我打电话给T.Factory
而不是XmlObject.Factory
),如果那就是&#39; s如何在不重复每个构建器实现中的工厂调用的情况下执行此操作。谢谢!
答案 0 :(得分:5)
假设所有构建的对象都有一个no-arg构造函数(以及一堆其他假设),你可以使用this idiom:
class Builder<SHAPE extends Shape> {
public final SHAPE shape = build();
@SuppressWarnings("unchecked")
private SHAPE build() {
try {
ParameterizedType parent =
(ParameterizedType) getClass().getGenericSuperclass();
Class<?> arg = (Class<?>) parent.getActualTypeArguments()[0];
return (SHAPE) arg.newInstance();
} catch (ReflectiveOperationException e) {
throw new RuntimeException(e);
}
}
public SHAPE shape() { return shape; }
}
但请注意,这可能会隐藏您的设计问题。
当您知道如何使用静态方法时,静态方法很方便,否则它们会咬你。如果不使用反射作弊,则必须通过在源代码中命名封闭类来调用静态方法,从而使代码实际上无法重用。此外,静态方法不是虚拟的,即子类不能覆盖父行为 - 再次,你可以通过使用反射作弊并自己调度调用。
构造
public class Foo<T extends MyOuter> {
public String bar() {
return T.MyNested.aStaticMethod();
}
}
访问类型变量上的静态成员很少见(demo)。方法签名在编译时被解析,因此T
的值没有被读取的机会(即使它是,类型参数也不会在Java的编译步骤中存活)。搜索的类型以递归方式解析,T
替换为其上限,从而导致类名XmlObject.Factory
。
答案 1 :(得分:1)
如何创建从构造函数调用的抽象方法?就像这样
public abstract class Builder<T extends XmlObject> {
abstract protected T createObject();
@SuppressWarnings("unchecked")
public Builder() {
xmlObject = (T) createObject();
}
}
然后在Time2SaveBuilder中,您只需实现它以返回正确的工厂实例。那应该是诀窍