Decorator Pattern in Java: Theory, Code Examples, and Practical Usage
This article explains the Decorator design pattern, compares a naïve inheritance approach with a proper decorator implementation in Java, provides complete code examples, class diagram, usage scenarios, advantages, and disadvantages, demonstrating how to dynamically extend object behavior without modifying existing code.
The Decorator Pattern (DecoratorPattern) allows adding responsibilities to objects dynamically without altering their original structure, offering a more flexible alternative to inheritance.
What Is the Decorator Pattern
It is a structural design pattern that attaches additional functionality to an object at runtime, keeping the original object unchanged.
Ordinary (Inheritance) Example
First, a simple Cake class is created:
package com.zwx.design.pattern.decorator.common;
import java.math.BigDecimal;
public class Cake {
public String getCakeMsg() {
return "我是一个8英寸的普通蛋糕";
}
public BigDecimal getPrice() {
return new BigDecimal("68");
}
}To add mango, a subclass overrides methods:
package com.zwx.design.pattern.decorator.common;
import java.math.BigDecimal;
public class CakeAddMango extends Cake {
@Override
public String getCakeMsg() {
return super.getCakeMsg() + "+1个芒果";
}
@Override
public BigDecimal getPrice() {
return super.getPrice().add(new BigDecimal("10"));
}
}Adding grape requires another subclass, leading to a proliferation of classes.
Decorator Implementation Example
Define an abstract Cake base class:
package com.zwx.design.pattern.decorator;
import java.math.BigDecimal;
public abstract class Cake {
public abstract String getCakeMsg();
public abstract BigDecimal getPrice();
}Concrete base cake:
package com.zwx.design.pattern.decorator;
import java.math.BigDecimal;
public class BaseCake extends Cake {
@Override
public String getCakeMsg() { return "我是一个8英寸的普通蛋糕"; }
@Override
public BigDecimal getPrice() { return new BigDecimal("68"); }
}Abstract decorator holding a Cake reference:
package com.zwx.design.pattern.decorator;
import java.math.BigDecimal;
public abstract class CakeDecorator extends Cake {
private Cake cake;
public CakeDecorator(Cake cake) { this.cake = cake; }
@Override
public String getCakeMsg() { return cake.getCakeMsg(); }
@Override
public BigDecimal getPrice() { return cake.getPrice(); }
}Concrete decorators for mango and grape:
package com.zwx.design.pattern.decorator;
import java.math.BigDecimal;
public class CakeAddMangoDecorator extends CakeDecorator {
public CakeAddMangoDecorator(Cake cake) { super(cake); }
@Override
public String getCakeMsg() { return super.getCakeMsg() + "+1个芒果"; }
@Override
public BigDecimal getPrice() { return super.getPrice().add(new BigDecimal("10")); }
} package com.zwx.design.pattern.decorator;
import java.math.BigDecimal;
public class CakeAddGrapeDecorator extends CakeDecorator {
public CakeAddGrapeDecorator(Cake cake) { super(cake); }
@Override
public String getCakeMsg() { return super.getCakeMsg() + "+1个葡萄"; }
@Override
public BigDecimal getPrice() { return super.getPrice().add(new BigDecimal("5")); }
}Test class demonstrating flexible composition:
package com.zwx.design.pattern.decorator;
public class TestCakeDecorator {
public static void main(String[] args) {
Cake cake = new BaseCake();
System.out.println(cake.getCakeMsg() + ",价格:" + cake.getPrice());
cake = new CakeAddMangoDecorator(cake);
System.out.println(cake.getCakeMsg() + ",价格:" + cake.getPrice());
cake = new CakeAddGrapeDecorator(cake);
System.out.println(cake.getCakeMsg() + ",价格:" + cake.getPrice());
cake = new CakeAddMangoDecorator(cake);
System.out.println(cake.getCakeMsg() + ",价格:" + cake.getPrice());
}
}Output:
我是一个8英寸的普通蛋糕,价格:68
我是一个8英寸的普通蛋糕+1个芒果,价格:78
我是一个8英寸的普通蛋糕+1个芒果+1个葡萄,价格:83
我是一个8英寸的普通蛋糕+1个芒果+1个葡萄+1个芒果,价格:93Class Diagram
The diagram shows an abstract Cake , a concrete BaseCake , the abstract CakeDecorator , and concrete decorators extending it.
Usage Scenarios
Extending a class's functionality or adding responsibilities.
Dynamically adding and possibly removing features at runtime.
Example: MyBatis second‑level cache uses the decorator pattern.
Advantages
Provides a flexible alternative to inheritance; can add features without modifying existing code.
Different decorators can be combined in various orders to achieve diverse behaviors.
Fully adheres to the Open/Closed Principle.
Disadvantages
Introduces many small classes, increasing code size and complexity.
Multiple layers of decoration can become hard to understand and maintain.
Overall, the decorator pattern enables clean, reusable extensions of object behavior, especially when requirements change frequently.
Selected Java Interview Questions
A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.