首先,我想承认这个问题与this other one非常相似,但我想问更多细节,希望得到更高质量的答案。
最近,我遵循了一个教程,其中的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}");
}
}
}随着教程的进行,我不禁想知道,为什么我们不把Director的唯一有意义的方法( BuildProduct方法)放到构建器的抽象基类中。这仍然可以确保所有具体的构建者都获得相同的构建模板,并消除看似无用的层。主任带来了什么好处?
在这里,我编写了几乎相同的代码,但没有使用director (Product省略了,因为它没有更改):
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();
}这两个方法输出相同的内容。我看到了这样一个提示,即您创建一个导演并与多个建设者一起重用它,它有一种顶层对象的感觉,它知道发生了什么(请原谅这里的模糊逻辑),但是您仍然需要了解和创建两个不同的构建器,那么为什么不直接使用它们呢?
发布于 2017-01-08 10:07:51
把Director的工作交给Builder是违反了单一责任原则的,因为Builder有两个责任:
BuildPart1和BuildPart2方法。实际上,例如,当您更改基类BuildPart1和BuildPart2调用的顺序时,所有具体的Thing*Builder(s)都会受到不必要的影响(必须重新编译和重新部署它们)。
发布于 2022-08-12 22:19:55
这是一个老问题,但这也是一个我发现自己说服其他开发人员足够频繁的主题,我认为我想提交一个迟来的答案无论如何。公认的答案是正确引用单一责任原则。我想补充的是一些更具体的想法,为什么这在第一时间如此重要。
Director/Builder是一种更通用的称为Bridge的模式的专门化,您可以通过共享接口将来自两个不同层次结构的实现对组合在一起。B类型的A和N实现的M实现产生了M*N独特的行为组合,用于M+N实现的开发和维护成本。
董事可以代表不同的原因或来源想要构建一个对象。建筑商可以生产不同的终端产品。有能力重用一个层次结构的每个实现与另一个层次的任何新实现都是生产力的巨大好处!
假设我开发了一个数据转换引擎,它需要一个对象图来描述它在运行时给出的每个任务。我为我的转换引擎提供了一种特定于域的语言,允许开发人员从他们的IDE中为它创建工作,我还有一个websocket协议,它允许网络服务提交工作单元。我还设计了一个关系数据库模式,用于支持一个中央存储库,用于托管转换引擎的云部署,并触发调度程序的执行。
我可以执行:
在Builder方面,我可能有:
我可以使用这些组合来完成多个相关用例,比为每个用例编写独立程序的速度要快得多:
后来,在我的产品的一生中,我可能会做一些重大改变的选择模型。我设法用第一个引擎的语义来表达所有可能的东西,但是用来指定相同行为的数据模型现在的形状非常不同。如何处理我们现有的用户群?
如果旧模型的语义仍然存在于新模型中,那么处理迁移的一种方法是提供一个新的构建器,它能够使用先前的接口定义其消息传递契约,但使用我的新对象模型实现它的等价意义。
目录/生成器对于MxN集成用例以及迁移/升级路径都是一个巨大的福音。
不管怎样,那是我的两分钱。:)
发布于 2017-01-07 00:04:52
您可以使用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();
}
}https://stackoverflow.com/questions/41516004
复制相似问题