C# 建筑商模式:导演的目的是什么?

C# 建筑商模式:导演的目的是什么?,c#,design-patterns,builder,C#,Design Patterns,Builder,首先,我想承认这个问题非常类似于,但我想问得更详细,希望能得到更高质量的答案 最近,我学习了一个教程,其中Builder模式是由一个Director实现的。为了演示,我简化了这些类: public class Director { private readonly Builder _builder; public Director(Builder builder) { _builder = builder; } public void

首先,我想承认这个问题非常类似于,但我想问得更详细,希望能得到更高质量的答案

最近,我学习了一个教程,其中Builder模式是由一个Director实现的。为了演示,我简化了这些类:

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}");
        }
    }
}
这两个示例的用法如下所示:

    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并将其与多个构建器重用,这让人感觉像是一个顶级对象,知道发生了什么(请原谅这里的模糊逻辑),但您仍然需要了解并创建两个不同的构建器,那么,为什么不直接使用它们呢?

您可以使用控制器来封装构建代码以及构建对象所需的步骤。在下面的示例中,您必须有一个RedCarBuilder和一个GreenCarBuilder来处理基类。我能找到的最好的例子:)

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

在您建议的示例中,当您不使用director时,生成器类看起来更像模板方法模式的示例

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

这方面的例子可以在

但是,在这里有其他版本的buillder模式

感谢和问候,
Chetan Ranpariya

主管
的工作交给
建筑商
违反了单一责任原则,因为
建筑商
将承担两项责任:

  • 建设者的责任:它知道如何实施
    BuildPart1
    BuildPart2
    方法
  • 董事的责任:它知道哪些部件应该用于 哪个订单

  • 实际上,例如,当您在基类
    Builder
    中更改对
    BuildPart1
    BuildPart2
    的调用顺序时,所有具体的
    Thing*Builder
    (必须重新编译和重新部署)都会受到不必要的影响。在我的示例中,目的是为要构建的产品的每个版本提供一个构建器。没有接球手或二传手。您似乎在回收构建器,但您的director实现很有趣,因为它为每种产品类型提供了一种方法。我可以看到,如果我的示例中的主管对每个产品都有一个方法,那么它就有了价值,从而允许客户不知道所有这些构建者。我觉得SRP的解释很有说服力。当这些问题如此抽象,并且在参考资料中没有提供更真实的解决方案时,我有时会与之斗争。重新编译/重新部署点是一个很好的例子,因为在我的关心中,它们是同一个程序集的一部分。在不同的环境中,我可以想象客户制作构建器并将它们与我的主管挂钩,让我了解构建顺序,而不必在构建顺序发生变化时强制对客户进行更改。简言之,这是一个好的、明确的答案,其中有分离的具体原因。
    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();
        }
    }