Comparison with the Decorator Pattern
I would call the design pattern used in previous examples (see References to Previous Articles below) as Agent Pattern at this point.
The Intent of Decorator Pattern
"Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality." (Green font is content quoted from Design Patterns - Elements of Reusable Object Oriented Software by GOF)
Obviously the Agent Pattern shares the same intent. Though previous examples do not have interfaces of withdrawing responsibilities, it is better to provide interfaces like "Deattach" to make the class more flexible for different projects.
"Sometimes we want to add responsibilities to individual objects, not to an entire class. A graphical user interface toolkit, for example, should let you add properties like borders or behaviors like scrolling to any user interface component."
Yes, the Agent Pattern has the same motivation.
- To add responsibilities to individual objects dynamically and transparently, that is, without affecting other objects.
- For responsibilities that can be withdrawn.
- When extension by subclassing is impractical. Sometimes a large number of independent extensions are possible and would produce an explosion of subclasses to support every combination. Or a class definition may be hidden or otherwise unavailable for subclassing.
Yes, the same applicability.
In the past, I used either of two forms above of the agent pattern.
From a certain point of view, the Agent Pattern is a simplified form of the Decorator pattern, without an abstract layer.
In the Decorator Pattern, the component has no knowledge of the decorator. In Agent Pattern, the component has references back to the Agent, since the Agent had subscribed some of the events of the component. Thus the agent can "decorate" the component when an event is fired.
From this point of view, the Agent Pattern is a composition of Decorator Pattern and Observer Pattern.
Sometimes the parameters of an event in the component provide some accesses to protected members, thus the Agent may have more power on component's data than a decorator can.
Collaborations of Decorator Pattern
- Decorator forwards requests to its Component object. It may optionally perform additional operations before and after forwarding the request.
In the agent pattern, the agent does decorating as well, and when the component fires events, the agent provides some event handling functions. The agent sometimes decorates the component on demand of events, or the component delegates the jobs to the agent.
Consequences of Decorator Pattern
The Decorator pattern has at least two key benefits and two liabilities:
More flexibility than static inheritance. The Decorator pattern provides a more flexible way to add responsibilities to objects than can be had with static (multiple) inheritance. With decorators, responsibilities can be added and removed at run-time simply by attaching and detaching them. In contrast, inheritance requires creating a new class for each additional responsibility (e.g.,
BorderedTextView). This gives rise to many classes and increases the complexity of a system. Furthermore, providing different
Decorator classes for a specific
Component class lets you mix and match responsibilities.
Decorators also make it easy to add a property twice. For example, to give a
TextView a double border, simply attach two
BorderDecorators. Inheriting from a
Border class twice is error-prone at best.
Avoids feature-laden classes high up in the hierarchy.
Decorator offers a pay-as-you-go approach to adding responsibilities. Instead of trying to support all foreseeable features in a complex, customizable class, you can define a simple class and add functionality incrementally with
Decorator objects. Functionality can be composed from simple pieces. As a result, an application needn't pay for features it doesn't use. It's also easy to define new kinds of
Decorators independently from the classes of objects they extend, even for unforeseen extensions. Extending a complex class tends to expose details unrelated to the responsibilities you're adding.
A decorator and its component aren't identical. A decorator acts as a transparent enclosure. But from an object identity point of view, a decorated component is not identical to the component itself. Hence you shouldn't rely on object identity when you use decorators.
Lots of little objects. A design that uses Decorator often results in systems composed of lots of little objects that all look alike. The objects differ only in the way they are interconnected, not in their class or in the value of their variables. Although these systems are easy to customize by those who understand them, they can be hard to learn and debug.
The agent pattern brings the same consequences.
Differences between Decorator Pattern and Agent Pattern
- In the decorator pattern, both the decorator and the component derive from the same base class. And you can have a decorator decorating another decorator.
- In the agent pattern, the component has knowledge of the agent through event bindings (observer pattern).
What is the Name of this Pattern?
Builder, Parasite, Help, Agent, Simplified Decorator, and Event Hijacker, I came across these names. Decorator looks like the closed one, and Agent was used by the other for Web design pattern. OK, I think I would call it Decorator Agent.
What do you think?
References to Previous Articles