Fundamentals 15 min read

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.

DaTaobao Tech
DaTaobao Tech
DaTaobao Tech
Understanding the Decorator Pattern in Java: Concepts, Implementation, and Comparison

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 Yuan

Comparison 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.

design patternsJavasoftware architectureCode ExampleDecorator Pattern
DaTaobao Tech
Written by

DaTaobao Tech

Official account of DaTaobao Technology

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.