6

我正在学习建造者模式

在上面的链接(Java 示例)中,我注意到 Builder 提供了构造多个组件的接口。除了调用它们,我们还调用了 getProduct()。

我不明白的一点是,为什么Director需要一个一个调用所有这些组件构造方法并最终得到结果。

     /** "Director" */
 class Waiter {
    private PizzaBuilder pizzaBuilder;


public void setPizzaBuilder(PizzaBuilder pb) { pizzaBuilder = pb; }
public Pizza getPizza() { return pizzaBuilder.getPizza(); }

public void constructPizza() {
   pizzaBuilder.createNewPizzaProduct(); 
   pizzaBuilder.buildDough(); // construct component 1
   pizzaBuilder.buildSauce(); // construct component 2
   pizzaBuilder.buildTopping();  // construct component 3
}

}

为什么不将构建组件1、2、3的代码包含在它自己的ConcreteBuilder类中而不是Director中,实际上去掉Director层。

我知道上述方法可能会将 Builder 模式转变为其他模式,但我不明白 Director 为何要一步一步地完成这项工作。有什么好处?如果有多个导演,就会有重复的代码,对吧?我可能不理解执行构建器模式背后的动机......

更新:构建器模式是否专注于在创建更大的复杂对象时提供可定制的组件选择?否则,截至目前,我没有看到引入额外层 Director 的意义。

即使是这样,装饰器模式也可能是一个更好的主意,通过动态自定义组件来完成同样的任务。在某个地方我错过了 Builder 背后的要点.. :(

4

4 回答 4

8

Director 类的目的是封装创建对象的算法,即将构造逻辑的代码与实际构成对象的部分的代码分开。如果没有 Director 类,您的 Builder 类将更加庞大且模块化程度更低,因此更难以维护且可重用性更低。

您所指的维基百科示例相当简单对于复杂的对象,构造机制通常要复杂得多,Director 不一定要按照定义的顺序逐一调用 Builder 方法。例如,考虑类Cake:它可能有部分ChocolateLayer和。Builder 将定义三个方法以按特定顺序构建这三个部分,但是Director 类中的方法可能如下所示:CreamLayerStrawberryconstructCake()

public void constructCake() {
   CakeBuilder.createNewCakeProduct(); 
   CakeBuilder.buildChocolateLayer(); 
   CakeBuilder.buildCreamLayer(); 
   CakeBuilder.buildChocolateLayer(); // 2nd call of the same Builder method
   int totalStrawberries = 3 + new Random().nextInt(2);
   for (int i = 1; i <= totalStrawberries; i++) 
      CakeBuilder.buildStrawberry(); // put some strawberries on top
   // Please don't try this recipe at home! 
}

至于 Builder 和 Decorator 之间的区别,您可以查看Builder Vs Decorator 模式问题。

于 2013-03-09T20:56:03.053 回答
7

Director 不构造对象,Builder 构造对象,它被称为 Product。Director 的存在有一个原因:因此该类的用户对构造对象所需的步骤一无所知。所有这些关于将其全部扁平化为一种方法的讨论就像在问为什么我们不能将汽车变成独轮车。我们只能一个。它不再是汽车了,而且 b. 它不能做汽车做的所有独轮车做不到的事情。

将 Builder 视为模板方法和工厂的融合的最佳方式之一:我们需要一个抽象的构造过程,以便我们可以支持不同产品的创建,但构造过程涉及许多步骤。这个想法是,一旦你有了 Director/Builder 架构,你就可以通过提供一个新的具体实现来轻松地添加新的 Builder。它类似于模板方法,因为 Builder 同样可以忽略构造语义的细节,而只提供构造的每个所需部分的实现(另请注意,某些逻辑可能最终在 Builder 层次结构的抽象基础中,进一步扩大了数量后来的扩展程序免费获得的自动功能)。

于 2013-03-09T23:41:31.687 回答
5

我认为您误解了构建器模式。您是说构建不同组件的过程可以合并到一个方法中,这是真的,但这不是此对象创建设计模式的关键。再看这段代码:

class Waiter {
    private PizzaBuilder pizzaBuilder;

    public void setPizzaBuilder(PizzaBuilder pb) { pizzaBuilder = pb; }
    public Pizza getPizza() { return pizzaBuilder.getPizza(); }

    public void constructPizza() {
        pizzaBuilder.createNewPizzaProduct();
        pizzaBuilder.buildDough();
        pizzaBuilder.buildSauce();
        pizzaBuilder.buildTopping();
    }
}

请注意,Waiter仅适用于 a PizzaBuilder,他不知道它是 aSpicyPizzaBuilder还是 a HawaiianPizzaBuilder,这是此模式的目标。在另一段代码中:

class BuilderExample {
    public static void main(String[] args) {
        Waiter waiter = new Waiter();
        PizzaBuilder hawaiianPizzaBuilder = new HawaiianPizzaBuilder();
        PizzaBuilder spicyPizzaBuilder = new SpicyPizzaBuilder();

        waiter.setPizzaBuilder( hawaiianPizzaBuilder );
        waiter.constructPizza();

        Pizza pizza = waiter.getPizza();

        waiter.setPizzaBuilder( spicyPizzaBuilder );
        waiter.constructPizza();

        Pizza anotherPizza = waiter.getPizza();
    }
}

您实际上可以看到这是如何工作的。AWaiter被创建并首先传递 a HawaiianPizzaBuilder,然后是 a SpicyPizzaBuilder,并且使用相同的实例,Waiter您可以构建一个比萨饼并要求它,他将提供正确的比萨饼。希望我已经解释了自己,并且此评论对您有所帮助;)祝您好运!!!

于 2013-03-09T06:11:50.923 回答
2

我对构建器模式的解释:让我们假设我们有一个对象(产品)并且对象构造需要许多参数或组件(其他对象),现在更糟糕的是,并非所有这些参数都可能需要,所以这将导致我们要么创建许多具有不同参数的构造函数,要么在唯一的构造函数中引入许多逻辑语句来选择这个对象并拒绝那个对象,更糟糕的是,这些组件可能需要按顺序(以特定顺序)构建,或者对它们进行一些业务规则检查,这一切归结为一个与参数(组件)紧密耦合且难以维护的复杂构造函数。解决方案是将这个逻辑移动到一个具体的构建器中,这样我们就可以通过调用来获取我们的对象ConcreteBuilder.BuildComponent1(), ConcreteBuilder.BuildComponent2(), ..., ConcreteBuilder.GetMeMyObject()但这会将客户端代码与构造过程紧密耦合,每个客户端现在都完全了解构造我们心爱的对象所需的所有步骤,因此构造过程中的任何更改都将迫使我们到处修改所有客户端代码,为了解决这个问题,Builder 模式引入了Director封装了这些步骤,现在所有客户端都调用Director上的 Build() 方法来构建对象。总而言之,Director 在那里,所以客户端代码不知道或紧密耦合到创建我们心爱的对象所需的步骤,现在为什么这些BuildComponent1(), BuildComponent2()方法是用来解决构建器模式的问题的builder 在这些方法中,我们甚至可以选择将某些具体构建器的实现留空,因为我们的最终对象(产品)不需要那个组件,我们现在已经将这个复杂的构建过程封装在远离我们心爱的对象的工作中最好不用担心如何自己构建它。

于 2013-03-09T23:30:17.290 回答