This post implements decorator pattern in <Head First Design Pattern>. Decorator Pattern attaches additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality. Similar withInheritance, decorators allow behavior to be extended without the need to modify existing code. Decorators have the same type as the components they decorate, yet change the behavior of their components by adding new functionality before or after method calls to the component.
- Ensure the context is: a single core (or non-optional) component,several optional embellishments or wrappers, and an interface that iscommon to all.
- Create a "Lowest Common Denominator" interface that makes allclasses interchangeable.
- Create a second level base class (Decorator) to support theoptional wrapper classes.
- The Core class and Decorator class inherit from the LCD interface.
- The Decorator class declares a composition relationship to the LCDinterface, and this data member is initialized in its constructor.
- The Decorator class delegates to the LCD object.
- Define a Decorator derived class for each optional embellishment.
- Decorator derived classes implement their wrapper functionality -and - delegate to the Decorator base class.
- The client configures the type and ordering of Core and Decoratorobjects.
The general class diagram is given by
The component class is an abstract class, providing uniform interface to use method A and method B.ConcreteComponent implements the general blueprint. Suppose we want some newBehavior(), at the meantime, we do not want to open the class the revise the code for ConcreteComponent, we could useConcereteDecotor, whose general definition is provided by abstract classDecorator. For the specific coffee price in the book, the class structure is shown below
The code for basic beverage is given by
class Beverage {
public:
Beverage(){ description = "Unknown Beverage!"; }
virtual ~Beverage() {}
virtual std::string getDescription() const { return description; }
virtual double cost() const = 0;
protected:
std::string description;
};
/* Basic Cofee Types Inherits Beverage
HouseBlend, DarkRoast, Espresso, Decaf */
class HouseBlend : public Beverage{
public:
HouseBlend() { description = "House Blend Coffee"; }
virtual double cost() const { return 0.89; }
};
class DarkRoast : public Beverage{
public:
DarkRoast() { description = "Dark Roast Coffee"; }
virtual double cost() const { return 0.99; }
};
class Espresso : public Beverage{
public:
Espresso() { description = "Espresso Coffee"; }
virtual double cost() const { return 1.99; }
};
class Decaf : public Beverage{
public:
Decaf() { description = "Decaf Coffee"; }
virtual double cost() const { return 1.05; }
};
The code for condiments is given by
class CondimentDecorator : public Beverage {
public:
CondimentDecorator() {
beverage = NULL;
}
CondimentDecorator(const Beverage* beverage_){
beverage = beverage_;
}
CondimentDecorator(const CondimentDecorator* cd){
this->beverage = cd->beverage;
}
void operator=(const CondimentDecorator* cd){
this->beverage = cd->beverage;
}
virtual ~CondimentDecorator(){
delete beverage;
beverage = NULL;
}
virtual std::string getDescription() const = 0;
protected:
const Beverage* beverage;
};
class Milk : public CondimentDecorator {
public:
Milk():CondimentDecorator(){}
Milk(const Beverage* beverage_):CondimentDecorator(beverage_){}
~Milk() {
delete beverage;
beverage = NULL;
}
std::string getDescription() const {
return beverage->getDescription() + ", Milk";
}
double cost() const {
return 0.10 + beverage->cost();
}
};
The main function calculates Espresso, Espresso+Milk, Espresso+Double Milk
#include <iostream>
#include <./beverage.hpp>
int main()
{
Beverage* beverage1 = new Espresso();
std::cout << beverage1->getDescription() << " $" << beverage1->cost() << std::endl;
Beverage* beverage2 = new Milk(beverage1);
std::cout << beverage2->getDescription() << " $" << beverage2->cost() << std::endl;
Beverage* beverage3 = new Milk(beverage2);
std::cout << beverage3->getDescription() << " $" << beverage3->cost() << std::endl;
return 0;
}
The result is