建造者模式:导演的目的是什么?

Builder Pattern: What is the purpose of the Director?

首先,我想承认这个问题与 this other one 非常相似,但我想问得更具体,并希望获得更高质量的答案。

最近我学习了一个使用 Director 实现 Builder 模式的教程。为了演示目的,我简化了 classes:

public class Director
{
    private readonly Builder _builder;

    public Director(Builder builder)
    {
        _builder = builder;
    }

    public void BuildProduct()
    {
        _builder.CreateProduct();
        _builder.BuildPart1();
        _builder.BuildPart2();
    }

    public Product GetProduct() => _builder.GetProduct();
}

public abstract class Builder
{
    protected Product Product;

    internal void CreateProduct()
    {
        Product = new Product();
    }

    internal Product GetProduct() => Product;

    internal abstract void BuildPart1();

    internal abstract void BuildPart2();
}

public class Thing1Builder : Builder
{
    internal override void BuildPart1() => Product.ThingStrings.Add("Thing-1 String-1");

    internal override void BuildPart2() => Product.ThingStrings.Add("Thing-1 String-2");
}

public class Thing2Builder : Builder
{
    internal override void BuildPart1() => Product.ThingStrings.Add("Thing-2 String-1");

    internal override void BuildPart2() => Product.ThingStrings.Add("Thing-2 String-2");
}

public class Product
{
    internal readonly ICollection<string> ThingStrings = new List<string>();

    public void Display()
    {
        foreach (string thingString in ThingStrings)
        {
            Console.WriteLine($"Thing string = {thingString}");
        }
    }
}

在学习教程的过程中,我不禁想知道为什么我们不直接将 Director 唯一有意义的方法(BuildProduct 方法)放入构建器的抽象基础 class .这仍然确保所有混凝土构建器获得相同的构建模板,并消除看似无用的层。 Director带来了哪些优势?

这里我编写了几乎相同的代码,只是没有导演(产品 class 被省略,因为它没有改变):

public abstract class BuilderWithoutDirector
{
    protected Product Product;

    public void CreateProduct()
    {
        Product = new Product();
        BuildPart1();
        BuildPart2();
    }

    public Product GetProduct() => Product;

    protected abstract void BuildPart1();

    protected abstract void BuildPart2();
}

public class Thing1BuilderWithoutDirector : BuilderWithoutDirector
{
    protected override void BuildPart1() => Product.ThingStrings.Add("Thing-1 String-1");

    protected override void BuildPart2() => Product.ThingStrings.Add("Thing-1 String-2");
}

public class Thing2BuilderWithoutDirector : BuilderWithoutDirector
{
    protected override void BuildPart1() => Product.ThingStrings.Add("Thing-2 String-1");

    protected override void BuildPart2() => Product.ThingStrings.Add("Thing-2 String-2");
}

这两个示例的用法如下所示:

    private static void UseWithDirector()
    {
        var director = new Director(new Thing1Builder());
        director.BuildProduct();
        var thing1 = director.GetProduct();

        director = new Director(new Thing2Builder());
        director.BuildProduct();
        var thing2 = director.GetProduct();

        thing1.Display();
        thing2.Display();
    }

    private static void UseWithoutDirector()
    {
        var builder1 = new Thing1BuilderWithoutDirector();
        builder1.CreateProduct();
        var thing1 = builder1.GetProduct();

        var builder2 = new Thing2BuilderWithoutDirector();
        builder2.CreateProduct();
        var thing2 = builder2.GetProduct();

        thing1.Display();
        thing2.Display();
    }

这两种方法输出相同的东西。我看到了 Director 版本的一个优势提示,因为您创建了一个 director 并将其与多个构建器一起重用,它有一种顶级对象的感觉,知道发生了什么(请原谅那里的模糊逻辑),但您仍然必须了解并创建两个不同的构建器,那么为什么不直接使用它们呢?

您可以使用Director来封装构造代码和构造对象所需的步骤。在下面的示例中,您必须有一个 RedCarBuilder 和一个 GreenCarBuilder 才能使用您的基础 class。我能找到的最好的例子:)

BuilderPattern 试图解决一个对象存在多个构造函数的问题,目的不同。例如,一个用于创建红色汽车的构造函数和另一个用于创建绿色汽车的构造函数。但是在代码中很难看出不同构造函数的作用。

public class Car
{
    public int Wheels { get; set; }

    public string Colour { get; set; }
}

public interface ICarBuilder
{
    void SetColour(string colour);
    void SetWheels(int count);

    Car GetResult();
}

public class CarBuilder : ICarBuilder
{
    private Car car;

    public CarBuilder()
    {
        this.car = new Car();
    }

    public void SetColour(string colour)
    {
        this.car.Colour = colour;
    }

    public void SetWheels(int count)
    {
        this.car.Wheels = count;
    }

    public Car GetResult() => car;
}

public class CarBuildDirector
{
    public Car ConstructRedCar()
    {
        CarBuilder builder = new CarBuilder();

        builder.SetColour("Red");
        builder.SetWheels(4);

        return builder.GetResult();
    }

    public Car ConstructGreenCar()
    {
        CarBuilder builder = new CarBuilder();

        builder.SetColour("Green");
        builder.SetWheels(4);

        return builder.GetResult();
    }
}

创建和使用构建器模式时不需要有主管。

在您建议的示例中,当您不使用 director 时,构建器 classes 看起来更像是模板方法模式的示例。

这里director的工作我认为是通过调用builder的各种方法来封装创建最终产品的逻辑class。

您可以在以下位置找到此示例 https://sourcemaking.com/design_patterns/builder/java/1

但是建议使用其他版本的构建器模式 http://www.javaworld.com/article/2074938/core-java/too-many-parameters-in-java-methods-part-3-builder-pattern.html

感谢和问候, Chetan Ranpariya

Director 的工作放入 Builder 违反了单一职责原则,因为 Builder 将有两个职责:

  1. Builder 的职责:知道如何实施 BuildPart1BuildPart2 方法。
  2. 导演的责任:知道哪些部分应该用在 哪个订单。

事实上,例如,当您更改 BuildPart1BuildPart2 基础 class Builder 中的调用顺序时,您所有的具体 Thing*Builder(s) 受到不必要的影响(必须重新编译和重新部署)。