生成器应该由工厂创建吗?

时间:2013-06-14 10:02:44

标签: oop design-patterns

复杂对象通常由Builder模式创建,其中Builder是专用于通过多种方法创建单个对象的对象。例如。 (伪代码):

class PersonBuilder
    PersonBuilder Named(string name)
        this.name = name
        return this

    PersonBuilder Aged(int age)
        this.age = age
        return this

    Person GetPerson()
        return new Person(this.name, this.age)

这种具有流畅界面的有状态结构在构建器模式中很常见:

myPerson = builder.Named("John").Aged(20).GetPerson();

因此,创建PersonBuilderFactory是否明智,您可以从中创建构建器?或者您是否应该依赖PersonBuilder并假设您的课程会注入一个新对象吗?后一种方法意味着当您创建Person时,您应该重置构建器。这里的最佳做法是什么?为什么?

5 个答案:

答案 0 :(得分:1)

在C#中,我喜欢以下模式(需要lambda函数):

var person = PersonBuilder.Create(p => p.Named("John").Aged(20));

它的实现方式如下:

class PersonBuilder
{
    private PersonBuilder() { /* ... */ }

    public static Person Create(Action<PersonBuilder> configure)
    {
        var builder = new PersonBuilder();
        configure(builder);
        return builder.Build();
    }

    // ...
}

答案 1 :(得分:1)

原来Builder pattern有一位董事 据我了解,导演将建筑工作包含在内。 如果您需要以某种方式重置构建器(例如,在内部构建器中调用TcpClient的dispose),请在director中执行此操作。

如何以及在何处实例化混凝土建造者?
例如,如果您有3种文档格式(TXT,PDF,Excel)并且用户可以在其中选择,则在这种情况下您将需要工厂

class BuilderFactory
{
  public IBuilder Create(DocumentType type)
  {
    if(type == DocumentType.TXT)
      return new TxtBuilder();

    if(type == DocumentType.Pdf)
      return new PdfBuilder();

    //...
  }
}

如果在应用程序执行时间构建器中相同,则可以将具体构建器放在config中(特别是如果使用DI)。
如果您在设计时了解具体构建器,则可以使用新的运算符。

答案 2 :(得分:0)

这很大程度上取决于你的构建器类......当我必须在XXXBuilderFactory创建中应用一些逻辑时,我更喜欢创建一个Builder,否则,我认为,只有构建器就足够了这样代码仍然更简单。

答案 3 :(得分:0)

(由于我的问题的评论员没有选择回答我会提供一个我认为可以接受的答案)

使您的Builder不可变是这个问题的答案。您可以利用实例可以访问另一个实例的私有成员的事实。因此原始的例子变成:

class PersonBuilder
    PersonBuilder(PersonBuilder copy) // copy constructor
        this.name = copy.name
        this.age = copy.age

    PersonBuilder Named(string name)
        newBuilder = new PersonBuilder(this)
        newBuilder.name = name
        return newBuilder

    PersonBuilder Aged(int age)
        newBuilder = new PersonBuilder(this)
        newBuilder.age = age
        return newBuilder

    Person GetPerson()
        return new Person(this.name, this.age)

这样,仍然可以像这样使用构建器:

myPerson = builder.Named("John").Aged(20).GetPerson();

但是,原始构建器对象将保持不变,并且可以重复使用。

感谢Ben James提出的建议。

答案 4 :(得分:-1)

一般来说,构建器应该是不可变的,不应该有重置的概念。但是这仍然取决于你需要实现的东西....