Fundamentals 5 min read

Decorator Pattern Explained: Simple Theory, Real‑World Scenarios, and Java Code

The article introduces the Decorator pattern, explains its purpose of dynamically adding functionality without altering existing classes, illustrates the concept with everyday analogies and a complete Java milk‑tea example, and lists typical use cases and common pitfalls.

liandk
liandk
liandk
Decorator Pattern Explained: Simple Theory, Real‑World Scenarios, and Java Code

What Is the Decorator Pattern?

In plain terms, the Decorator pattern lets you layer additional responsibilities onto an object at runtime without modifying the original class or creating a large hierarchy of subclasses. Its core goal is dynamic feature extension, offering flexible composition instead of complex inheritance.

Real‑World Scenarios

Milk‑tea ordering: the base drink is the core object, and toppings such as pearls, coconut jelly, or milk foam are added layer by layer as decorators.

Software examples: I/O stream buffering, log enhancement, request signing, caching, or retry logic.

UI components: a basic dialog can be wrapped with a mask, animation, or watermark.

Java Implementation (Milk‑Tea Example)

1. Abstract Drink Interface

public interface Drink {
    // Get price
    double getPrice();
    // Get description
    String getDesc();
}

2. Concrete Base: Plain Milk Tea

public class MilkTea implements Drink {
    @Override
    public double getPrice() {
        return 10.0;
    }
    @Override
    public String getDesc() {
        return "原味奶茶";
    }
}

3. Abstract Decorator Holding a Drink

public abstract class DrinkDecorator implements Drink {
    protected Drink drink;
    public DrinkDecorator(Drink drink) {
        this.drink = drink;
    }
}

4. Concrete Decorators: Pearl and Milk Cap

// Pearl decorator
public class Pearl extends DrinkDecorator {
    public Pearl(Drink drink) { super(drink); }
    @Override
    public double getPrice() { return drink.getPrice() + 2; }
    @Override
    public String getDesc() { return drink.getDesc() + "+珍珠"; }
}

// MilkCap decorator
public class MilkCap extends DrinkDecorator {
    public MilkCap(Drink drink) { super(drink); }
    @Override
    public double getPrice() { return drink.getPrice() + 3; }
    @Override
    public String getDesc() { return drink.getDesc() + "+奶盖"; }
}

5. Test Invocation

public class Test {
    public static void main(String[] args) {
        // Plain milk tea + pearl + milk cap
        Drink tea = new MilkCap(new Pearl(new MilkTea()));
        System.out.println(tea.getDesc() + ",总价:" + tea.getPrice());
    }
}

Common Business Use Cases

When you need to add multiple optional features to an object dynamically.

Inheritance would lead to a proliferation of subclasses (class explosion).

JDK I/O streams such as FileReader, BufferedReader, LineNumberReader illustrate the pattern.

Request enhancement: unified logging, permission checks, caching, failure retries.

Data processing: layering encryption, masking, or format conversion.

Pitfalls to Avoid

The Adapter pattern focuses on converting interfaces for compatibility, whereas the Decorator pattern enhances existing functionality without changing the original interface. Mixing the two can lead to design confusion.

Conclusion

The ninth episode on the Decorator pattern wraps up with a clear definition, a four‑layer structure (abstract component, concrete component, abstract decorator, concrete decorator), and practical scenarios ranging from I/O streams to API request augmentation.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

design patternsjavasoftware architectureCode ExampleDecorator PatternObject-Oriented
liandk
Written by

liandk

Seasoned Java and mobile developer with years of experience, specializing in mini‑programs, public accounts, and full‑stack front‑end development. In the AI era, I continuously learn to broaden my knowledge and evolve. I revived a public account I started a decade ago during a dessert‑startup venture, using code as a vessel and knowledge as a companion. I share personal projects, technical articles, programming tips, and growth insights—let’s improve together and set sail.

0 followers
Reader feedback

How this landed with the community

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.