The decorator pattern attaches additional responsibilities to an object dynamically. Decorators provide a flexible alternative to sub-classing for extending functionality.
Aims to avoid 'class chaos'. Uses open / closed principle. Add new behaviour, but without implementing regression. Uses delegation and composition.
The 'component' is the abstract thing, and the decorators are the concrete things that implement it. Any decorator should be able to be wrapped to any abstract component.
Example
Abstract Component
class Beverage {
constructor() {
this.description = "unknown beverage"
}
getDescription() {
return description;
}
getCost() {
return cost;
}
}
class HouseBlend extends Beverage {
constructor() {
this.description = "House Blend Coffee";
}
cost() {
return .89;
}
}
class Espresso extends Beverage {
constructor() {
this.description = "Espresso";
}
cost() {
return 1.99;
}
}
class Milk extends CondimentDecorator {
constructor() {
this.beverage = beverage
}
getDescription() {
return beverage.getDescription() + ", Milk";
}
cost() {
return .10 + beverage.cost()
}
}
Decorating time!
const beverageOne = new Espresso();
beverageOne.getDescription();
beverageOne.getCost();
// doesn't need any decorating.
const beverageTwo = new HouseBlend();
beverageTwo = new Milk(beverageTwo);
beverageTwo.getDescription();
// => blah blah + milk.
beverageTwo.getCost();
// => milk + house blend cost added together.