Attaches additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality
- Base Component: Defines the interface for objects that can have responsibilities added to them dynamically.
- ConcreteComponent: Defines an object to which additional responsibilities can be attached.
- Decorator: Maintains a reference to a Component object and defines an interface that conforms to Component's interface.
- ConcreteDecorator: Adds responsibilities to the component.
- 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.
- More flexibility than static inheritance. (Open/Closed Principle)
- Avoids feature-laden classes high up in the hierarchy.
- A decorator and its component aren't tightly coupled.
- Can add functionality to individual objects at runtime.
- Can have multiple decorators for a single component.
- Decorators can result in many small objects in our design, and overuse can be complex.
- Often used with other patterns such as Factory and Builder.
- Can lead to a system with a large number of small objects that look similar but are actually different.
Check the src
directory for the implementation of the observer pattern in TypeScript.
To run the main file (src/index.ts) and see the output, run
ts-node src/index.ts
in your terminal.N/B: You must have
ts-node
installed globally to run the command above. If you don't have it installed, you can install it by runningnpm install -g ts-node
.