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.
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
...
}
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:
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.
Add behaviour to object at run time. Inheritance is the key to achieve this functionality, which is both advantage and disadvantage of this pattern.
It enhances the behaviour of interface.
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.
Decorator supports recursive composition
Decorator is designed to let you add responsibilities to objects without sub-classing
When to use Decorator:
Object responsibilities and behaviours should be dynamically added/removed
Concrete implementations should be decoupled from responsibilities and behaviours
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")));
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.
发布评论
评论(4)
来自维基百科的装饰器模式文章:
披萨完全制作完成后,无需添加配料。你不会吃掉半个披萨,然后再添加另一种配料。
换句话说,构建器模式可以轻松地构造一个在构造时可以在独立方向上扩展的对象,而装饰器模式可以让您在构造之后向对象添加功能扩展。 em> 施工时间。使用装饰器模式构造对象是不好的,因为它会使对象处于不一致(或至少不正确)的状态,直到所有必需的装饰器就位为止 - 类似于使用 setter 指定可选构造函数参数的 JavaBean 问题。
From wikipedia's decorator pattern article:
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.
您混淆了两种截然不同的事物。 GoF 将 Builder 归类为创建型模式,而 Decorator 则归类为结构型模式。它们的描述如下(Gamma 等人,第 1 页):
请注意装饰器的重点。它是子类化的灵活替代方案。子类化用于建模is-a关系。奶酪不是披萨。披萨由多种成分组成,通常使用组合来建模。
构建器模式在这里是相关的,因为成分数量如此之多,以至于需要以标准化的方式构建它们。
举一个装饰器的真实示例,我最近想记录在我的 java 应用程序中使用 jdbc 执行的查询。我通过实现一个名为 LoggingConnection 的类来实现这一点,该类扩展了 Connection 接口。
这允许我传递连接的具体实现,并在运行时扩展其功能。在这种情况下子类化会出现问题,因为您不一定知道实际返回的连接对象是什么。这是因为它是使用 DriverManager 工厂为您构建的:
在本例中,conn 对象是驱动程序中包含的实现,我通常不知道其名称。装饰器方法的优点在于我不必知道,并且它不依赖于特定的实现。
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):
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.
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:
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.
让我们看一下Builder 和Decorator 的主要特征。
Builder:(一种创建模式)
Decorator:(结构模式)
何时使用 Decorator:
回到您的查询:
Builder 是 Pizza 的正确创建模式。披萨最初是用强制性成分(面包等)制作的。奶酪、意大利辣香肠、培根是可选成分,但它们仍然可以在制作过程中成为披萨的一部分。
装饰器对于在运行时为已创建的对象添加动态职责非常有用。
例如:
有关更多详细信息,请参阅以下帖子:
将构建器分开class(流畅的接口)
何时使用装饰器模式?
Lets go through key characteristics of Builder and Decorator.
Builder: ( A Creational pattern)
Decorator: ( A Structural pattern)
When to use Decorator:
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. :
Refer to below posts for more details:
Keeping builder in separate class (fluent interface)
When to Use the Decorator Pattern?
构建器模式专门用于构建和装饰器以在构建后添加特殊功能。
例如,在上面的披萨示例中,我们可以根据问题域决定使用两种模式之一。
如果辣椒片对于披萨是必不可少的,并且类似地,我们有很多成分可以添加到披萨中,其中很少有是使披萨可食用(有意义的状态)的基本成分,那么我们可以更喜欢使用 Builder。
一旦披萨制作完成,我们就可以用番茄酱、橄榄等不同的配料来装饰它……
而且,上面正确地指出它们可以一起使用,但这会增加复杂性。因此,我们应该仅在问题域需要时才明智地使用模式,否则简单的构造就足够了。
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.