Builder模式:为什么Director构造对象?

时间:2013-03-09 04:10:45

标签: oop design-patterns ooad builder-pattern

我正在学习Builder Pattern

在上面的链接(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
}

}

为什么我们不在ConcreteBuilder类中包含构建组件1,2,3的代码,而不是在Director中,实际上消除了Director层。

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

UPDATE :在创建更大的复杂对象时,Builder模式是否专注于提供可自定义组件选择?否则,截至目前,我没有看到引入附加层的重点,即Director。

即使是这种情况,Decorator模式也可能是通过动态定制组件来实现相同目标的更好方法。在某处,我忽略了Builder背后的一点...... :(

4 个答案:

答案 0 :(得分:6)

Director不构造对象,Builder构建对象,它被称为Product。 Director有一个原因:这样的类用户对构造对象所需的步骤一无所知。所有这些谈论只是把它拼凑成一种方法就像问为什么我们不能把汽车变成独轮车。我们可以但是。它不再是一辆车了,而且b。它不能完成汽车所做的所有单轮脚踏车所不能做的事情。

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

答案 1 :(得分:5)

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

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仅适用于PizzaBuilder,他不知道它是SpicyPizzaBuilder还是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();
    }
}

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

答案 2 :(得分:5)

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

您所指的Wikipedia example相当简单。对于复杂的对象,构造机制通常涉及更多,并且Director不一定按照它们的定义顺序调用Builder方法。例如,考虑Cake类:它可能包含部分ChocolateLayerCreamLayerStrawberry。 Builder将按照这个特定的顺序定义构建这三个部分的三种方法,但是Director类中的constructCake()方法可能如下所示:

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 pattern问题。

答案 3 :(得分:1)

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