Builder Vs Decorator pattern [closed]
Asked Answered
H

4

47

From When would you use the Builder Pattern?,

It is said that builder pattern is appropriate for Pizza example.

Why not Decorator ? by treating Cheese, Pepperoni, Bacon as additional decorations on a base pizza.

Is it for the reason that Cheese/Pepperoni have to be built seperately. I don't think, they need to be built seperately as they can be available readymade.

Pls clarify. Am also looking for a good real-world example of decorator pattern and reason why it is the apt for that particular example. Thank you.

Hallowmas answered 22/1, 2011 at 14:22 Comment(1)
I had the same thought when i learned this with the example. Prof couldn't help me, but this does, thanks!Vesuvian
N
63

From wikipedia's decorator pattern article:

In object-oriented programming, the decorator pattern is a design pattern that allows new/additional behaviour to be added to an existing object dynamically.

There's no need to add toppings to a Pizza after it has been fully constructed. You don't eat half a pizza and then add another topping to it.

In other words, the Builder Pattern makes it easy to construct an object which is extensible in independent directions at construction time, while the Decorator Pattern lets you add extensions to functionality to an object after construction time. Using the decorator pattern to construct objects is bad because it leaves the object in an inconsistent (or at least incorrect) state until all the required decorators are in place - similar to the JavaBean problem of using setters to specify optional constructor arguments.

Nainsook answered 22/1, 2011 at 14:44 Comment(6)
potter: Actually, some toppings like kitchup, chilli flakes will be given along with Pizza. So can we say we apply both patterns ? First builder then Decorator ?Hallowmas
potter: +1, My above assumption seem to be correct about toppings, got from #2707901Hallowmas
@bjs: yes, the decorator and builder can be sensibly combined, and your example is one possibility; however, it leads to a complex design and less readable code. I'd only use Builder + Decorator if I were sure it was actually required by the project and not just a case of "Pattern Fever" on my part. Consider whether it might be worth just adding an addChilli() method to the base class rather than building a full blown ChilliDecorator. (As always, there is no correct answer.)Nainsook
A builder would be a reasonable way to apply decorators to an object. You could certainly use a builder to decorate a pizza and return the fully decorated pizza object from the builder. I would say the two patterns have a habit of working hand in hand.Paiz
In addition to what @PhilipPotter said, if you use the builder pattern, you would only be able to do this at compile time because you need to know exactly what methods to call in the chain of builders. (Example : pizza.Builder().withCheese().withOnions().build() ). Compare this to the decorator pattern where you can use a factory to decorate your Pizza based on runtime inputs (Example : factory.createPizza(String []toppings)). Inside the factory, you can iterate through the toppings and decorate the Pizza (Example : if("cheese".equals(toppings[i]) { pizza = new PizzaWithCheese(pizza) } )Attu
So if I had an object FoodItem where it can be either a Sandwich or a Pizza (since decided at runtime , choosing decorator pattern) , they can have different implementation of make() method and functionality based on the type of foodItem, and furthermore their make() can have a builder pattern of their own , does this make sense ?Philter
C
26

You are confusing two very different things. GoF classifies Builder as a creational pattern, while Decorator is a structural pattern. They are described as follows (Gamma et al, page 1):

Builder (97) Separate the construction of a complex object from its representation so that the same construction process can create different representations.

Decorator (175) Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.

Note the emphasis on the decorator. It's a flexible alternative to subclassing. Subclassing is used to model an is-a relationship. Cheese is not a pizza. The pizza is composed of a number of ingredients, and that is usually modeled using composition.

The builder pattern is relevant here because there are such a vast number of ingredients that the need arises to construct them in a standardized way.

To take a real world example of a decorator, I recently wanted to log the queries executed using jdbc in my java application. I accomplished this by implementing a class called LoggingConnection which extended the Connection interface.

public class LoggingConnection implements Connection
{
    public static class LogEntry
    {
        public String sql;
        public int invocationCount;
        public double avgTime;
        public double maxTime;
    }

    private Connection delegate;

    private Map<String, LogEntry> log;

    public LoggingConnection(Connection delegate)
    {
        this.delegate = delegate;
        this.log = new HashMap<String, LogEntry>();
    }

    public Map<String, LogEntry> getLog()
    {
        return log;
    }

    @Override
    public void clearWarnings()
    throws SQLException
    {
        delegate.clearWarnings();
    }

    @Override
    public void close()
    throws SQLException
    {
        delegate.close();
    }

    // forwarding declarations to all other methods declared in the interface
    ...
}

This allows me to pass a concrete implemention of a connection, and extend its functionality at runtime. Subclassing would be problematic in this context, because you don't necessarily know what connection object is actually returned. This is because it's constructed for you using the DriverManager factory:

Connection conn = DriverManger.getConnection(dsn);

The conn object is in this case an implementation contained in the driver, which I generelly don't know the name of. The beuty of the decorator approach is that I don't have to know, and that it isn't tied to a specific implementation.

Covariance answered 22/1, 2011 at 14:41 Comment(5)
Well, an "alternative" suggests that subclassing could also be used. The subclassing alternative isn't to make cheese a subclass of pizza, but rather have a cheese pizza subclass of pizza. Since a cheese pizza is a pizza.Neogene
@Lèse: But it's conceivable that you could implement a decorator that adds the same "cheese" functionality like a subclass does. The only major difference would be that you can decide to make the extension at runtime instead.Covariance
@Emil: Right, a decorator is still a better, more flexible pattern in this case. I was just pointing to the equivalent if you were going the subclassing route.Neogene
@Lèse: Alright. Fair point. :)Covariance
The decorator implements the pizza and its incredients. The builder constructs the chain of implementations. They are completely seperated concerns. Both parts could exist without the other one ... The builder does not really need to know if the implementation is using a Decorator or is just a kind of composition.Bollinger
K
9

Lets go through key characteristics of Builder and Decorator.

Builder: ( A Creational pattern)

  1. Too Many arguments to pass from client program to the Factory class that can be error prone
  2. Some of the parameters might be optional unlike in Factory which forces to send all parameters
  3. Object is heavy and its creation is complex. e.g. building various types of pizzas

Decorator: ( A Structural pattern)

  1. Add behaviour to object at run time. Inheritance is the key to achieve this functionality, which is both advantage and disadvantage of this pattern.
  2. It enhances the behaviour of interface.
  3. Decorator can be viewed as a degenerate Composite with only one component. However, a Decorator adds additional responsibilities - it isn't intended for object aggregation.
  4. Decorator supports recursive composition
  5. Decorator is designed to let you add responsibilities to objects without sub-classing

When to use Decorator:

  1. Object responsibilities and behaviours should be dynamically added/removed
  2. Concrete implementations should be decoupled from responsibilities and behaviours
  3. When sub - classing is too costly to dynamically add/remove responsibilities

Coming back to your query:

Builder is right creational pattern for Pizza. Pizza is created with mandatory ingredients initially ( Bread etc). Cheese, Pepperoni, Bacon are optional ingredients but still they can be part of pizza during build process.

Decorator is useful for adding dynamic responsibilities at run-time for already created object.

e.g. :

BufferedInputStream bis = new BufferedInputStream(new FileInputStream(new File("a.txt")));

Refer to below posts for more details:

Keeping builder in separate class (fluent interface)

When to Use the Decorator Pattern?

Kumamoto answered 13/8, 2016 at 17:29 Comment(0)
T
4

The builder pattern is specifically used to build and Decorator to add special features post build. e.g In the Pizza example above we can decide to use one of the two pattern based on the problem domain.

If Chilli Flakes are essential for a Pizza and similarly we have a lot of ingredients to add to Pizza out of which few are elementary to make the Pizza edible(meaningful state), we can prefer to use Builder. Once the Pizza is constructed, we can later go and decorate it with different toppings like tomato sauce, olives, etc...

Also, it is stated above correctly that they can be used together but this will increase complexity. So we should use patterns wisely only when it is needed in the problem domain, else a simple construction will suffice.

Thai answered 22/2, 2014 at 19:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.