3

我今天在 SO 的某个地方看到了一种设计模式,用于说明 Java 中关于不可变对象的观点。这个想法是允许用户在构造过程中为他想要的任何属性设置值,它看起来像这样:

MyObject obj = new MyObject().name("Foo")
                             .height(5)
                             .width(3)
                             .color("blue")
                             .age(7);

这种模式有名字吗?

在 C++ 中,我知道你可以this在每个函数中返回一个指针。它是如何在 Java 中以同样的方式完成的?

对于不可变对象,您是否必须为要设置的每个属性制作对象的新副本?

4

4 回答 4

3

如果你想构造一个大致具有这种风格的不可变对象,你可能需要Builder 模式

这里可见的链接也称为Fluent 接口,确实可以通过返回来启用this

使用您的代码在正在构建的实际对象上使用流利的接口,如果所有设置事物的方法实际上都是 mutators,则该对象将不是不可变的。如果这些方法都返回一个新对象而不是this它可能是不可变的。

于 2012-09-20T22:23:07.430 回答
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);
   }
}
于 2012-09-20T22:21:45.460 回答
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属性相同的属性。obj1name

这通常是长构造函数的替代方法。它还可以用于所有信息都不能立即获得的对象,并且您不想在需要创建对象的任何地方自己声明一堆变量。从最后一个示例中,您可以看到,如果您想要使用相同的属性初始化大量对象,而不必一遍又一遍地传递这些属性,则可以使用它。

结果是您拥有一个不可变对象,但您不必像使用构造函数或静态工厂方法那样同时设置/传递所有变量。

以下是一些参考资料:

于 2012-09-20T22:29:08.157 回答
0

这是建造者模式的一个例子。

更典型的用法是:

MyObject obj = new MyObjectBuilder().name("Foo").blah().build();

请注意使用不同的构建器类。

于 2012-09-20T22:19:39.327 回答