是否有像#34; build-once"建设者?

时间:2015-10-22 19:57:37

标签: java builder

我们的框架提供了某种" log"对象;它实际上代表了我们遗留的C / C ++代码中的遗留结构。今天我开始编写一个帮助器类,它使用构建器模式来允许更现代的方法来创建这样的日志对象。

但有一个问题,我不确定答案是正确的:

基本上这些日志对象有一些属性是必需的&#34 ;;因此,遵循构建器模式,您必须将这些参数指定为我的新构建器类的ctor的参数。然后构建器有一些方法来配置"可选属性&#34 ;;当然还有一种方法" build()"这将发出一个日志对象,其中包含所收集值的摘要。

但现在我想知道:我是否应该关心人们是否会重新使用相同的构建器对象?那么,我应该有一个" reset()"清除所有可选参数的方法;或者防止不止一次调用build()? 或者最好不要担心不是全部?

3 个答案:

答案 0 :(得分:2)

无需重置,只需继续允许使用相同的构建器对象生成新对象。开发人员可以创建一个新构建器,以避免重复使用先前设置的内容。此外,Twitter4j有这样的东西(并且是开源的),如果你想看看事情应该如何运作(见http://twitter4j.org/en/configuration.html):

ConfigurationBuilder cb = new ConfigurationBuilder();
cb.setDebugEnabled(true)
  .setOAuthConsumerKey("*********************")
  .setOAuthConsumerSecret("******************************************")
  .setOAuthAccessToken("**************************************************")
  .setOAuthAccessTokenSecret("******************************************");
TwitterFactory tf = new TwitterFactory(cb.build());
Twitter twitter = tf.getInstance();

答案 1 :(得分:2)

  

我是否应该关心人们是否会重复使用相同的构建器对象?

你想要观察副作用,但我认为这就是你问的原因,因为你知道人/代码会在建造者中留下垃圾。

  

那么,我应该有一个" reset()"清除所有可选参数的方法;

我认为如果你传递一个构建器,清理的责任应该在使用者身上(将构建器作为输入的函数或类)。这样我们就不会造成副作用。例如:

public class SomeClass {
    public SomeClass(Log.Builder builder){
       builder.tag("SomeClass"); //bad, we caused a side effect
                                 //someone class forgets to set the tag
                                 //later, then they get this tag
       log = builder.build();
    }
}

一种解决方案是提供复制构造函数:

public class SomeClass {
    public SomeClass(Log.Builder builder){
       Log.Builder localBuilder = new Log.Builder(builder); //copy constructor being used.
       localBuilder.tag("SomeClass"); //only applies to the local builder
       log = localBuilder.build();
    } //builder is as it was before the call, no side effect
}

您甚至可以使用副本致电SomeClass,这样您就不需要关心它是否实现了无副作用:

Log.Builder defaults = new Log.Builder(...whatever...).tag("notag");
new SomeClass(new Log.Builder(defaults));
new SomeClass2(new Log.Builder(defaults));

要进一步锁定它,你可以拥有一个界面Log.ReadOnlyBuilder,它没有设置器,并且真的只适合构建或创建副本:

public class Log {
    public interface ReadOnlyBuilder {
        Builder copy();
        Log build();
    }

    public static class Builder implements ReadOnlyBuilder {
        Builder tag(String tag){
          ...
        }
    }
}

public class SomeClass {
    public SomeClass(Log.ReadOnlyBuilder builder){
       log = builder.copy().tag("SomeClass").build();
    } //builder is as it was before the call, no side effect
}

我喜欢这个,因为消费者的责任不会引起副作用,但它通过类型和界面得到强制执行。此外,如果他们不需要设置任何字段,他们可以只使用readonly构建器,我们不必为了以防万一而制作副本。

P.S。我不认为可选和必需是你想要决定重置什么和设置什么的分界点。我认为复制构造函数应该只将构建器中的每个字段复制到新构建器。但是你可以随意开发copy方法/构造函数。

答案 2 :(得分:0)

我发现在这种情况下有用的东西,当构建器被多次重复使用并且可能存在一些剩余的数据重叠时,是要在构建器类中构建未初始化的对象,并保留初始化对构建器实例的责任。这样,构建的对象不关心(或知道)以前构建的会话中的垃圾剩余,如果它需要相同的可选数据,构建器也知道重新初始化该数据。