构建者设计模式。为什么我们需要一个总监?[英] Builder design pattern: Why do we need a Director?

本文是小编为大家收集整理的关于构建者设计模式。为什么我们需要一个总监?的处理/解决方法,可以参考本文帮助大家快速定位并解决问题,中文翻译不准确的可切换到English标签页查看源文。

问题描述

最近,我遇到了构建器设计模式.似乎不同的作者使用"建筑商模式"来指代不同的口味,所以让我描述我要问的模式.

我们有一种用于创建 products 的算法,即不同类型的对象.在足够高的抽象水平上,所有产品类型的算​​法都是相同的,但是每种产品类型都需要对每个算法的抽象步骤进行不同的实现.例如,我们可能具有以下蛋糕烘烤算法:

 1. Add liquids.
 2. Mix well.
 3. Add dry ingredients.
 4. Mix well.
 5. Pour batter into baking pan.
 6. Bake.
 7. Return baked cake.

不同的蛋糕将需要这些步骤的不同实现,即要使用哪种液体/干成分,混合速度,烘烤多长时间等等.

模式说要这样做.对于每种产品,我们创建A 混凝土构建器类,并针对上述每个步骤进行实现.所有这些类均来自抽象构建器基类,这实际上是接口.因此,例如,我们将使用纯虚拟方法AddLiquid(),MixLiquids()等具有抽象的基类CakeBaker.混凝土蛋糕面包师将是混凝土子类,例如,

class ChocolateCakeBaker : public CakeBaker {
public:
   virtual void AddLiquids()
   {
        // Add three eggs and 1 cup of cream
   }

   virtual void AddDryIngredients()
   {
       // Add 2 cups flour, 1 cup sugar, 3 tbsp cocoa powder,
       // 2 bars ground chocolate, 2 tsp baking powder
   }
      ...
      ...
};

LemonCitrusCakeBaker也将是CakeBaker的子类,但会在其方法中使用不同的成分和数量.

不同的蛋糕类型将类似地是抽象Cake基类的子类.

最后,我们有一个可以实现抽象算法的类.这是董事.在面包店示例中,我们可能称其为ExecutiveBaker.此类将接受(从客户端)接受混凝土构建器对象,并使用其方法来创建和返回所需的产品.

这是我的问题.为什么我们需要导演与抽象建设者分开?为什么不将它们滚入单个建筑商抽象基类,使原始的抽象建筑商的公共方法受到保护(并且混凝土子类像以前一样覆盖这些方法).

推荐答案

构建器模式的核心部分涉及抽象构建器及其子类(混凝土构建器).根据 GOF的设计模式,董事简单地"通知构建产品时,可以建立产品的一部分",这可以由客户端.

stringbuilder Java api中的没有各自的主任 - 通常客户类"指导" IT.

另外,在 and http://www.drdobbs.com/jvm/creating-anding-anding-and------销毁 - java-objects-par/208403883?pgno = 2">创建和破坏Java对象,Joshua Bloch建议使用建造者模式,他不包括导演.

其他推荐答案

没有董事的构建器模式的GOF变化没有建造者.有一个不同的观点,但我会进一步解释.

构建器模式的观点是为您提供多种创建相同对象的方法.构建器应只有构建对象的不同部分的方法,但是算法 - 执行这些功能的方式 - 应该是导演的关注点.没有导演,每个客户将需要确切知道建筑物的运作方式.但是,在主任的情况下,所有客户都需要知道的是在特定情况下要使用的建筑商.

所以,我们这里有两个部分:

  1. 构建器,一个一个一个一个一个一个一个一个一个一个.要注意的重要事项是,为此,它保留了创建对象的状态.
  2. 主任控制建造者的功能的执行方式.

现在我早些时候指的是.模式的建设者部分在其他情况下很有用,并且在没有董事的情况下使用了不同目的的不同供应商.这种用途的具体示例是学说查询构建器.

这种方法的缺点是,当构建器开始构建一个对象时,它就变得陈述了,如果客户在创建对象之后未重置构建器 - 另一个客户或已被多次使用的客户端可以获取先前创建的对象的一部分.因此,学说使用工厂模式来创建构建器的每个实例.

我希望这有助于那些谷歌搜索的人.

其他推荐答案

如果您分为董事和建筑商,您已经记录了从一组零件(主管)组装产品的不同责任和创建零件(建筑商)的责任.

  • 在构建器中,您可以更改零件的构建方式.在您的情况下,无论是AddLiquid()是否应该添加奶油或牛奶.
  • 在导演中,您可以更改如何组装零件.在您的情况下,使用AddChocolate()而不是AddFruits()您会得到其他蛋糕.

如果您想要这种额外的灵活性,我会重命名为(因为在建筑商中使用贝克建议,这是组装零件的建筑商工作)

class LightBakingSteps : public BakingSteps {
public:
    virtual void AddLiquids()
    {
        // Add milk instead of cream
    }

    virtual void AddDryIngredients()
    {
        // Add light sugar
    }

    ...
};

class ChoclateCakeBaker : public CakeBaker {
public:
     Cake Bake(BakingSteps& steps)
     {
         steps.AddLiquieds();
         steps.AddChocolate();      // chocolate instead of fruits
         return builder.getCake();
     }
}

本文地址:https://www.itbaoku.cn/post/627779.html

问题描述

Recently I've come across the Builder design pattern. It seems that different authors use "Builder pattern" to refer to different flavours, so let me describe the pattern I'm asking about.

We have an algorithm for creating products, i.e., objects of different types. At a sufficiently high level of abstraction the algorithm is the same for all product types, but each product type requires a different implementation of each of the algorithm's abstract steps. For example, we might have the following cake-baking algorithm:

 1. Add liquids.
 2. Mix well.
 3. Add dry ingredients.
 4. Mix well.
 5. Pour batter into baking pan.
 6. Bake.
 7. Return baked cake.

Different cakes would require different implementations of these steps, i.e., what liquids/dry ingredients to use, what speed to mix at, how long to bake, etc.

The pattern says to do it like so. For each product we create a concrete builder class with an implementation for each of the above steps. All of these classes are derived from an abstract builder base class, which is essentially an interface. So, for example, we will have an abstract base class CakeBaker with pure virtual methods AddLiquid(), MixLiquids(), etc. The concrete cake bakers will be concrete subclasses, e.g.,

class ChocolateCakeBaker : public CakeBaker {
public:
   virtual void AddLiquids()
   {
        // Add three eggs and 1 cup of cream
   }

   virtual void AddDryIngredients()
   {
       // Add 2 cups flour, 1 cup sugar, 3 tbsp cocoa powder,
       // 2 bars ground chocolate, 2 tsp baking powder
   }
      ...
      ...
};

The LemonCitrusCakeBaker would also be a subclass of CakeBaker, but would use different ingredients and quantities in its methods.

The different cake types will similarly be subclasses of an abstract Cake base class.

Finally, we have a class to implement the abstract algorithm. This is the director. In the bakery example we might call it ExecutiveBaker. This class would accept (from the client) a concrete builder object and use its methods in order to create and return the desired product.

Here's my question. Why do we need the director to be separate from the abstract builder? Why not roll them into a single builder abstract base class, making the original abstract builder's public methods protected (and the concrete subclasses override these as before).

推荐答案

The core portion of the Builder pattern concerns the Abstract Builder and its subclasses (concrete builders). According to GoF's Design Patterns, director simply "notifies the builder whenever a part of the product should be built", which can be perfectly done by the client.

The StringBuilder class in the Java API is an example of a builder without the respective director -- typically the client class "directs" it.

Also, in Effective Java and Creating and Destroying Java Objects, Joshua Bloch suggests the use of the builder pattern, and he does not include a director.

其他推荐答案

The GoF variation of the Builder pattern does NOT have the Builder WITHOUT the Director. There's a different point to this, but I'll explain further.

The Builder pattern's point is to give you multiple ways to create the same object. Builder should only have methods which build different parts of an object, but the algorithm - the way these functions are executed - should be the concern of the Director. Without the Director every client would have the need to know EXACTLY how the building works. But with the Director all the Client needs to know is what Builder to use in a specific case.

So, what we have here are two parts:

  1. The Builder, that creates parts of the object one by one. The important thing to note is that for this it keeps state of the created object.
  2. The Director, that controls the way Builder`s functions are executed.

Now to the point I was referring earlier. The Builder part of the pattern is useful in other cases and has been used by different vendors WITHOUT the Director for different purposes. A concrete example of such use would be the Doctrine Query Builder.

The disadvantage of such approach is when the Builder starts to build an object it becomes stateful and if the Client doesn't reset the Builder after the object was created - another Client or the same Client that has been used more than once could get the parts of the object that was created earlier. For this reason, Doctrine uses the Factory pattern to create every instance of the Builder.

I hope this helps those googling.

其他推荐答案

If you separate into Director and Builder you have documented the different responsibility of assembling a product from a set of parts (director) and the responsibility of creating the part (builder).

  • In the builder you can change how a part is build. In your case whether a AddLiquid() should add cream or milk.
  • In the director you can change how to assemble the parts. In your case a by using AddChocolate() instead of AddFruits() you get a different cake.

If you want this extra flexibility, I would rename to (since using baker in the builder suggests, it was the builders job of assembling the parts)

class LightBakingSteps : public BakingSteps {
public:
    virtual void AddLiquids()
    {
        // Add milk instead of cream
    }

    virtual void AddDryIngredients()
    {
        // Add light sugar
    }

    ...
};

class ChoclateCakeBaker : public CakeBaker {
public:
     Cake Bake(BakingSteps& steps)
     {
         steps.AddLiquieds();
         steps.AddChocolate();      // chocolate instead of fruits
         return builder.getCake();
     }
}