Learning Design Patterns - Decorator Pattern

This week I'll be hanging the Decorator Pattern in my series on design patterns plucked from this book and from examples on the Internet.

What is it?
An important design rule is to design your code to be open for extension, but closed for modification, and the Decorator Pattern is one way to go about extending existing code. The decorator wraps up an existing object and then adds functionality to it; and since the decorator is of the same type as the object it wraps, the effect should be seamless for client code (unless client code is relying on the concrete type of the original object).

Where is it used?
The Decorator Pattern is used to extend existing code without modifying it and to create a highly configurable design that relies less on inheriting behaviors and more on composition.
The pattern has some potential downsides. Applying it can result in a lot of small classes that can confuse someone new to the code, can cause type errors if the client code is relying on the concrete class that is wrapped up in the decorator objects, and it adds some complexity when trying to initiate components.
Targeting the areas of your application that are most prone to change would be a good start to considering where to apply this pattern.

But why?
Why not just add instance variables to a superclass, then use inheritance to set their values in sub classes? If those instance variables are not going to grow or change over time you could opt for simplicity in design over extensibility. The Decorator Pattern can help when those attributes are going to fluctuate; it can provide a way to extend the functionality without touching the existing code, which will reduce the chance of unintended consequences.

OK, and how is it implemented?

//Java
public abstract class EscortService {
	String description = "Unknown Service";
	public String getDescription() {
		return description;
	}
	public abstract double cost();
}
// create the decorator
public abstract class EscortServiceDecorator extends EscortService {
	public abstract string getDescription();
}
// create the concrete classes 
public class Monica extends EscortService {
	public Monica() {
		description = "Monica, a beautiful brunette";
	}
	public double cost() {
		return 350.00;
	}
}
public class Charlie extends EscortService {
	public Charlie() {
		description = "Charlie, a former Chipendale Dancer";
	}
	public double cost() {
		return 169.00;
	}
}
// create the decorations
public class Dinner extends EscortService {
	EscortService es;
	public Dinner(EscortService es) {
		this.es = es;
	}
	public string getDescription() {
		return es.getDescription() + ", have dinner";
	}
	public double cost() {
		//add on to base fee
		return 45.00 + es.cost();
	}
}
public class Nightcap extends EscortService {
	EscortService es;
	public Nightcap(EscortService es) {
		this.es = es;
	}
	public string getDescription() {
		return es.getDescription() + ", have a nightcap";
	}
	public double cost() {
		//add on to base fee
		return 95.00 + es.cost();
	}
}

// Example use
public class RandysEscorts {
	//could use factory pattern to decouple "Monica" use
	EscortService es = new Monica();
	//prints: Monica, a beautiful brunette $350.00
	System.out.println(es.getDescription() + " $" + es.cost();
	
	//Add dinner and a nightcap
	es = new Dinner(es);
	es = new Nightcap(es);
	//prints: Monica, a beautiful brunette, have dinner, have a nightcap $490.00
	System.out.println(es.getDescription() + " $" + es.cost();
}