Fundamentals 12 min read

Mastering the Decorator Pattern: Real‑World Java Examples for Extensible Code

This article explains the Decorator design pattern, presents its UML structure, describes the roles of abstract components, concrete components, and decorators, and demonstrates three practical Java scenarios—task processing, file I/O, and logging—showing how to extend functionality without modifying existing classes.

Baidu Geek Talk
Baidu Geek Talk
Baidu Geek Talk
Mastering the Decorator Pattern: Real‑World Java Examples for Extensible Code

Design patterns are essential skills for writing clean code; the Decorator pattern provides a solution for repeatedly occurring problems in object‑oriented design by allowing new behavior to be added to existing objects without altering their source.

UML Overview

The generic class diagram consists of an Abstract Component (interface or abstract class), one or more Concrete Components , an Abstract Decorator that holds a reference to a component, and Concrete Decorators that extend the abstract decorator to add functionality.

Decorator Pattern UML Diagram
Decorator Pattern UML Diagram

Component Roles

Abstract Component (Component) : defines the methods that both concrete components and decorators must implement.

Concrete Component (ComponentA, ComponentB) : the original classes that provide core functionality.

Abstract Decorator (Decorator) : usually an abstract class that stores a reference to a component and declares the same interface.

Concrete Decorator (DecoratorX, DecoratorY) : subclasses of the abstract decorator that add or modify behavior.

Example 1 – Task Processing

In a scenario where a message must be sent after a task finishes, the following structure is used:

Abstract component TaskProcessor with method process().

Concrete components TaskProcessorA and TaskProcessorB implement the core task logic.

Abstract decorator TaskProcessDecorator holds a TaskProcessor reference.

Concrete decorator AfterTaskProcessDecorator calls the original process() and then executes afterProcess() to send a notification.

package com.baidu.demo;
public class Decorator {
    // Abstract component
    static abstract class TaskProcessor {
        abstract void process();
    }
    // Concrete components
    static class TaskProcessorA extends TaskProcessor {
        @Override void process() { System.out.println("TaskProcessorA处理完成"); }
    }
    static class TaskProcessorB extends TaskProcessor {
        @Override void process() { System.out.println("TaskProcessorB处理完成"); }
    }
    // Abstract decorator
    static abstract class TaskProcessDecorator extends TaskProcessor {
        protected TaskProcessor processor;
        public TaskProcessDecorator(TaskProcessor processor) { this.processor = processor; }
        abstract void process();
    }
    // Concrete decorator
    static class AfterTaskProcessDecorator extends TaskProcessDecorator {
        public AfterTaskProcessDecorator(TaskProcessor processor) { super(processor); }
        @Override void process() { processor.process(); afterProcess(); }
        void afterProcess() { System.out.println("任务处理完毕,发送消息..."); }
    }
    public static void main(String[] args) {
        System.out.println("==========before==========");
        TaskProcessor processorA = new TaskProcessorA();
        processorA.process();
        TaskProcessor processorB = new TaskProcessorB();
        processorB.process();
        System.out.println("==========after==========");
        TaskProcessor decoratorA = new AfterTaskProcessDecorator(processorA);
        decoratorA.process();
        TaskProcessor decoratorB = new AfterTaskProcessDecorator(processorB);
        decoratorB.process();
    }
}

Example 2 – File I/O

The Decorator pattern is applied to stream handling, where a basic InputStream reads bytes, FileInputStream extends it to work with files, and BufferedInputStream adds caching.

// Basic component
public abstract class InputStream {
    public int read(byte[] b, int off, int len) { /* ... */ }
}
// Concrete decorator – file stream
public class FileInputStream extends InputStream {
    protected InputStream in;
    public FileInputStream(String name) { /* create underlying stream */ }
    @Override public int read(byte[] b, int off, int len) { return in.read(b, off, len); }
}
// Concrete decorator – buffered stream
public class BufferedInputStream extends FileInputStream {
    protected FileInputStream in;
    protected byte[] buffer;
    public BufferedInputStream(FileInputStream in) { this.in = in; }
    @Override public int read(byte[] b, int off, int len) {
        if (buffer == null || buffer.length == 0) {
            in.read(buffer, 0, in.length());
        }
        System.arraycopy(buffer, off, b, 0, len);
        // additional logic ...
        return len;
    }
}
public static void main(String[] args) {
    FileInputStream fs = new FileInputStream("./test.log");
    BufferedInputStream bs = new BufferedInputStream(fs);
    byte[] b = new byte[1];
    bs.read(b, 0, 1);
}

Example 3 – Logging System

In a logging framework, different alert channels (email, SMS, flow) are combined using decorators. The abstract Log interface defines logging methods; Slf4jLog provides a concrete implementation. LogDecorator forwards calls, while specific decorators ( MailLogDecorator, SMSLogDecorator, InfoflowLogDecorator) add side‑effects such as sending notifications.

public interface Log {
    void debug(String message);
    void info(String message);
    void warn(String message);
    void error(String message);
}
public class Slf4jLog implements Log { /* uses LoggerFactory */ }
public class LogDecorator implements Log {
    protected Log log;
    public LogDecorator(Log log) { this.log = log; }
    @Override public void debug(String m) { log.debug(m); }
    @Override public void info(String m) { log.info(m); }
    @Override public void warn(String m) { log.warn(m); }
    @Override public void error(String m) { log.error(m); }
}
public class MailLogDecorator extends LogDecorator {
    public MailLogDecorator(Log log) { super(log); }
    @Override public void warn(String m) { super.warn(m); mail(m); }
    @Override public void error(String m) { super.error(m); mail(m); }
    void mail(String m) { log.info("邮件已发送,信息:" + m); }
}
public class SMSLogDecorator extends LogDecorator {
    public SMSLogDecorator(Log log) { super(log); }
    @Override public void error(String m) { super.error(m); send(m); }
    void send(String m) { log.info("短信已发送,信息:" + m); }
}
public class InfoflowLogDecorator extends LogDecorator {
    public InfoflowLogDecorator(Log log) { super(log); }
    @Override public void warn(String m) { super.warn(m); send(m); }
    @Override public void error(String m) { super.error(m); send(m); }
    void send(String m) { log.info("如流消息已发送,信息:" + m); }
}
public class LogTest {
    @Test public void testLogDecorator() {
        Log log = new SMSLogDecorator(
            new InfoflowLogDecorator(
                new MailLogDecorator(new Slf4jLog())));
        log.debug("系统调试开启");
        log.info("系统正常运行");
        log.warn("数据为空警告");
        log.error("db 连接错误");
    }
}

Conclusion

The Decorator pattern enables flexible extension of existing classes while adhering to the Open/Closed Principle; the three examples—task processing, file I/O, and logging—illustrate how to add responsibilities without modifying the original code base.

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 ArchitectureDecorator PatternObject-Oriented
Baidu Geek Talk
Written by

Baidu Geek Talk

Follow us to discover more Baidu tech insights.

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.