我正在解析一个XML文件,其中必须在创建对象后设置其中一个我想要不可变的字段ID。我应该将它设置为null,并在setID()方法中抛出异常,如果ID!= null?
编辑: 我正在解析一个XML文件,在开始时,我创建了一个对象,其字段和对象使用XML文件中的信息填充。我希望能够在创建根对象后设置ID,它应该是不可变的。
编辑:将“final”更改为“immutable”,因为这真的是我在语义上的意思。 (对不起:()
答案 0 :(得分:14)
最常见的方法是use the builder pattern。使用setter构建对象,然后在准备就绪后,使用构建器作为模板创建不可变对象。
答案 1 :(得分:9)
您无法在构造函数之外更改最终成员。你必须让它不是最终的。
答案 2 :(得分:7)
更好的方法可能是使用构建器,如第2项中的Effective Java 2nd Edition中所述。
基本思想是让一个Builder类具有不同构造函数参数的setter(但通常不是getter)。还有build()
方法。 Builder类通常是用于构建的类的(静态)嵌套类。外部类的构造函数通常是私有的。
最终结果如下:
public class Foo {
public static class Builder {
public Foo build() {
return new Foo(this);
}
public Builder setId(int id) {
this.id = id;
return this;
}
// you can set defaults for these here
private int id;
}
public static Builder builder() {
return new Builder();
}
private Foo(Builder builder) {
id = builder.id;
}
private final int id;
// The rest of Foo goes here...
}
要创建Foo的实例,您可以编写如下内容:
Foo foo = Foo.builder()
.setId(id)
.build();
当然,您也可以将其拆分:
// I don't know the ID yet, but I want a place to store it.
Foo.Builder fooBuilder = Foo.builder();
...
// Now I know the ID:.
fooBuilder.setId(id);
...
// Now I'm done and want an immutable Foo.
Foo foo = fooBuilder.build();
您可以在构建器上安装多个setter,甚至可以为build()或Builder的构造函数添加其他参数。
这使您可以在解析时拥有可变对象,但在完成后切换到不可变对象。在许多情况下,您的API只需要公开不可变对象。
答案 3 :(得分:6)
根据定义,最终字段在构造对象后不会更改。 如果您真正想要的是您希望将字段设置一次,那么您可以简单地将该字段初始化为null,如果该字段不再为null,则该字段的setter会抛出异常。
答案 4 :(得分:1)
你绝对不能成功final
。如果setID()
是个好主意,则从ID != null
引发例外。也许如果你提供更多细节,有人可以提出更有创意的解决方案吗?
答案 5 :(得分:0)
除非在构造期间初始化该字段,否则无法声明该字段final
。我认为这样的事情可能符合你的要求。
class Foo {
private Bar x;
void setX(Bar x) {
if (x == null)
throw new IllegalArgumentException();
if (this.x != null)
throw new IllegalStateException();
this.x = x;
}
}
此Foo
实现旨在供单个线程访问。对于多线程访问,您可以使用AtomicReference
或外部synchronize
访问权限。
另请注意,如果null
是x
的有效值,则可以创建一个私有的虚拟Bar
实例,并使用它代替null
。
答案 6 :(得分:0)
也许这个好的lib会帮助你解析xml XStream,所以你不必为创建对象而烦恼。我不知道你是否可以按你想要的方式配置它,但我确定它值得一看。
我会尝试使用公共setId方法,因为如果没有某个客户端可以调用的问题,你可以解决这个问题。尝试使用该语言告诉用户他可以做什么以及他不应该做什么。
如果你没有将id存储在xml文件中,你应该使用一个工厂来创建对象并使用参数化的构造函数。
如果您没有为id提供setter,用户只能在创建对象时“设置”id,我认为这就是你想要的。
答案 7 :(得分:0)
从技术上讲,如果您可以在执行构造函数后更改该值,则它不是“不可变的”。它更“可模仿”。
但是除了术语之外:我想到的第一个想法就是拥有某种“验证”功能。浏览所有的安装人员,当您认为已完成时,请致电验证。如果失败,则该对象缺少必填字段或其他内容。
构建器对象的想法也很好。我从来没有使用过这种模式。 '必须考虑利弊。