interface Coffee {
double cost();
String description();
}
class SimpleCoffee implements Coffee {
public double cost() { return 2.0; }
public String description() { return "Simple Coffee"; }
}
abstract class CoffeeDecorator implements Coffee {
protected Coffee coffee;
CoffeeDecorator(Coffee coffee) {
this.coffee = coffee;
}
public double cost() { return coffee.cost(); }
public String description() { return coffee.description(); }
}
class Milk extends CoffeeDecorator {
Milk(Coffee coffee) { super(coffee); }
public double cost() { return coffee.cost() + 0.5; }
public String description() {
return coffee.description() + " + Milk";
}
}
class Sugar extends CoffeeDecorator {
Sugar(Coffee coffee) { super(coffee); }
public double cost() { return coffee.cost() + 0.3; }
public String description() {
return coffee.description() + " + Sugar";
}
}
public static void main(String[] args) {
Coffee coffee = new SimpleCoffee();
coffee = new Milk(coffee);
coffee = new Sugar(coffee);
System.out.println(coffee.description()
+ " $" + coffee.cost());
}The Decorator pattern attaches additional responsibilities to an object dynamically. It provides a flexible alternative to subclassing for extending functionality by wrapping an object with one or more decorator classes that implement the same interface. Each decorator adds its own behavior before or after delegating to the wrapped object.