我今天在SO上看到了一个设计模式,用于说明Java中不可变对象的观点。这个想法是允许用户在构造期间为他想要的任何属性设置值,它看起来像这样:
MyObject obj = new MyObject().name("Foo")
.height(5)
.width(3)
.color("blue")
.age(7);
这个模式有名称吗?
在C ++中我知道你可以在每个函数中返回指向this
的指针。如何在Java中以相同的方式完成?
对于不可变对象,您是否必须为要设置的每个属性创建对象的新副本?
答案 0 :(得分:3)
如果你想构建一个大约有这种风格的不可变对象,你可能想要Builder pattern。
此处可见的链接也称为Fluent interface,确实通过返回this
启用。
使用您正在构建的实际对象上的fluent接口的代码,如果所有设置事物的方法实际上都是mutator,则该对象将不会是不可变的。如果这些方法都返回一个新对象而不是this
,那么它可能是不可变的。
答案 1 :(得分:1)
这不是其他人评论中提到的Builder模式。
这是http://en.wikipedia.org/wiki/Fluent_interface,它相似但不一样。
我认为你的最后两个问题有些相关,因为你可以以可变和不可变的方式实现这种模式。
如果你实现它是可变的,那么对于每个方法,你改变状态并返回:
public class UsefulThing {
Integer state;
public UsefulThing(Integer state) {
this.state=state;
}
public UsefulThing alter(Integer newState) {
state = newState;
return this;
}
}
对于不可变的实现,您可以根据提供的对象创建一个新对象并返回该对象。
public class UsefulThing {
Integer state;
public UsefulThing(Integer state) {
this.state=state;
}
public UsefulThing alter(Integer newState) {
return new UsefulThing(newState);
}
}
答案 2 :(得分:1)
这看起来像构建器模式的一种形式(虽然它确实不是)。
通常(使用您的示例并假设它是不可变的)它遵循类似于此的模式:
public class MyObject {
private final String name;
private final int height;
private final int width;
private final String color;
private final int age;
private MyObject(Builder builder) { // Notice this is private
name = builder.name;
height = builder.height;
width = builder.width;
color = builder.color;
age = builder.age;
}
// Getters
public static class Builder {
// Initialize these to defaults if you have any
private String name;
private int height;
private int width;
private String color;
private int age;
// Getters as usual
// Every setter looks like this:
public Builder setName(String name) {
this.name = name;
return this;
}
// Other setters
public MyObject build() {
return new MyObject(this);
}
}
}
然后使用它:
MyObject obj = new MyObject.Builder()
.setName("Foo")
.setHeight(5)
.setWidth(3)
.setColor("blue")
.setAge(7)
.build();
您还可以重复使用构建器:
MyObject.Builder builder = new MyObject.Builder();
MyObject obj1 = builder
.setName("Foo")
.setHeight(5)
.setWidth(3)
.setColor("blue")
.setAge(7)
.build();
MyObject obj2 = builder
.setName("Bar")
.build();
此处obj2
除了obj1
之外,其他所有属性都与name
具有相同的属性。
这通常是长构造函数的替代方法。它也可以用于所有信息都不能立即获得的对象,并且您不希望在创建对象所需的任何地方声明一堆变量。从上一个示例中,您可以看到,如果您想要使用相同的属性初始化大量对象而不必反复传递这些属性,则可以使用它。
结果是你有一个不可变对象,但你不必像使用构造函数或静态工厂方法那样同时设置/传递所有变量。
以下是一些参考资料: