Understanding the Decorator Pattern in Java: Concepts, Implementation, and Comparison
The article explains Java’s Decorator pattern, detailing its four roles, how to build abstract components and concrete decorators, demonstrates dynamic runtime extension of object behavior through sample code, compares it with inheritance, Proxy and Adapter patterns, and outlines its advantages, drawbacks, and suitable use cases.
The article introduces the core idea of the Decorator pattern: creating a decorator object to dynamically extend the functionality of a target object without altering its structure, offering a more flexible alternative to inheritance.
Overview
Design patterns improve code reusability, maintainability, extensibility, and readability. The Decorator pattern belongs to the structural category of the 23 classic design patterns.
Basic Concepts
The pattern consists of four roles: Abstract Component, Concrete Component, Abstract Decorator, and Concrete Decorator. The Abstract Decorator holds a reference to an Abstract Component and delegates calls while adding behavior.
Structure
Role
Relation
Purpose
Abstract Component
Parent of Concrete Component and Abstract Decorator
Defines the abstract interface for target objects
Concrete Component
Implements the abstract interface
Represents the original object to be decorated
Abstract Decorator
Inherits/implements Abstract Component and holds a component reference
Provides a base for concrete decorators
Concrete Decorator
Extends Abstract Decorator
Adds specific additional behavior
Usage Steps
Create an Abstract Component defining the core methods.
Implement a Concrete Component.
Define an Abstract Decorator that stores a component reference.
Create Concrete Decorators that override methods to add functionality.
Code Implementation
public interface ItemComponent {
double checkoutPrice();
}
public class ConcreteItemCompoment implements ItemComponent {
@Override
public double checkoutPrice() { return 200.0; }
}
public abstract class ItemAbsatractDecorator implements ItemComponent {
protected ItemComponent itemComponent;
public ItemAbsatractDecorator(ItemComponent myItem) { this.itemComponent = myItem; }
@Override
public double checkoutPrice() { return this.itemComponent.checkoutPrice(); }
}
public class ShopDiscountDecorator extends ItemAbsatractDecorator {
public ShopDiscountDecorator(ItemComponent myItem) { super(myItem); }
@Override
public double checkoutPrice() { return 0.8 * super.checkoutPrice(); }
}
public class FullReductionDecorator extends ItemAbsatractDecorator {
public FullReductionDecorator(ItemComponent myItem) { super(myItem); }
@Override
public double checkoutPrice() { return super.checkoutPrice() - 20; }
}
public class BybtCouponDecorator extends ItemAbsatractDecorator {
public BybtCouponDecorator(ItemComponent myItem) { super(myItem); }
@Override
public double checkoutPrice() { return super.checkoutPrice() - 50; }
}
public class UserPayForItem {
public static void main(String[] args) {
ItemComponent item = new ConcreteItemCompoment();
System.out.println("Original price: " + item.checkoutPrice() + " Yuan");
item = new ShopDiscountDecorator(item);
System.out.println("After shop discount: " + item.checkoutPrice() + " Yuan");
item = new FullReductionDecorator(item);
System.out.println("After full reduction: " + item.checkoutPrice() + " Yuan");
item = new BybtCouponDecorator(item);
System.out.println("After coupon: " + item.checkoutPrice() + " Yuan");
}
}Result Output
Original price: 200.0 Yuan
After shop discount: 160.0 Yuan
After full reduction: 140.0 Yuan
After coupon: 90.0 YuanComparison with Other Patterns
Unlike inheritance, the Decorator adds behavior at runtime, allowing selective feature activation. Compared with the Proxy pattern, Decorator focuses on extending functionality, while Proxy emphasizes controlling access. Compared with the Adapter pattern, Decorator and the target share the same interface, whereas Adapter can bridge incompatible interfaces.
Advantages
Provides flexible, dynamic extension without subclass explosion.
Decorators and components can evolve independently.
Disadvantages
Multiple layers of decorators increase object count and can make debugging harder; excessive dynamic composition may reduce maintainability.
Applicable Scenarios
When inheritance leads to class explosion or the target class is final.
When you need to add or remove responsibilities to individual objects dynamically.
Summary
The Decorator pattern is easy to understand, aligns with the Open/Closed Principle, and is widely used in Java I/O (e.g., FilterInputStream) and many frameworks such as Spring Cache and MyBatis.
DaTaobao Tech
Official account of DaTaobao Technology
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.