Fundamentals 12 min read

Understanding the Decorator Pattern with Practical Java Examples

This article explains the Decorator Pattern—a design pattern that lets developers extend object behavior without modifying existing code—by describing its core components, showing a generic UML diagram, and providing three detailed Java case studies covering task processing, file I/O, and logging systems.

Architecture Digest
Architecture Digest
Architecture Digest
Understanding the Decorator Pattern with Practical Java Examples

Design patterns are essential skills for writing good code; this article introduces the Decorator Pattern, which allows adding responsibilities to objects without modifying their source.

The pattern consists of an abstract component, concrete components, an abstract decorator, and concrete decorators. A generic UML diagram illustrates these relationships.

Three practical Java examples demonstrate the pattern:

1. Task processing scenario – abstract TaskProcessor , concrete TaskProcessorA / TaskProcessorB , abstract TaskProcessDecorator , concrete AfterTaskProcessDecorator that adds a notification after processing. The full source code is shown below.

package com.baidu.demo;
public class Decorator {
    // 抽象组件
    static abstract class TaskProcessor {
        abstract void process();
    }
    // 具体组件
    static class TaskProcessorA extends TaskProcessor {
        @Override
        void process() {
            System.out.println("TaskProcessorA处理完成");
        }
    }
    // 具体组件
    static class TaskProcessorB extends TaskProcessor {
        @Override
        void process() {
            System.out.println("TaskProcessorB处理完成");
        }
    }
    // 抽象装饰器
    static abstract class TaskProcessDecorator extends TaskProcessor {
        protected TaskProcessor processor;
        public TaskProcessDecorator(TaskProcessor processor) {
            this.processor = processor;
        }
        abstract void process();
    }
    // 具体装饰器
    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();
    }
}

2. File I/O scenario – abstract InputStream , concrete FileInputStream as a decorator that adds file handling, and BufferedInputStream as a further decorator that adds buffering. The implementation code follows.

// 具体组件,实现读取字节流
public abstract class InputStream {
    public int read(byte b[], int off, int len) {}
}
// 具体装饰器,作为 InputStream 的子类,扩展文件操作
public class FileInputStream extends InputStream {
    protected InputStream in;
    public FileInputStream(String name) {
        InputStream in = ... // 此处省略,通过文件名创建对象
        this.in = in;
    }
    public int read(byte b[], int off, int len) {
        return this.in.read(b, off, len);
    }
}
// 具体装饰器,作为 FileInputStream 的子类,扩展缓存操作
public class BufferedInputStream extends FileInputStream {
    protected FileInputStream in;
    protected byte[] buffer;
    public BufferedInputStream(FileInputStream in) {
        this.in = in;
    }
    public int read(byte b[], int off, int len) {
        if (this.buffer == null || this.buffer.length == 0) {
            this.in.read(this.buffer, 0, in.lenght());
        }
        System.arraycopy(this.buffer, off, b, 0, len);
        ...
    }
}
public static void main(String[] args) {
    FileInputStream fs = new FileInputStream('./test.log');
    BufferedInputStream bs = new BufferedInputStream(fs);
    byte[] b;
    bs.read(b, 0, 1);
}

3. Logging system scenario – Log interface as the abstract component, Slf4jLog as the concrete component, LogDecorator as the abstract decorator, and MailLogDecorator , SMSLogDecorator , InfoflowLogDecorator as concrete decorators that add email, SMS, and flow notifications. The corresponding Java code is provided.

public interface Log {
    void debug(String message);
    void info(String message);
    void warn(String message);
    void error(String message);
}
public class Slf4jLog implements Log {
    private final Logger log = LoggerFactory.getLogger("system_log");
    @Override public void debug(String message) { if (log.isDebugEnabled()) log.debug(message); }
    @Override public void info(String message) { if (log.isInfoEnabled()) log.info(message); }
    @Override public void warn(String message) { if (log.isWarnEnabled()) log.warn(message); }
    @Override public void error(String message) { if (log.isErrorEnabled()) log.error(message); }
}
public class LogDecorator implements Log {
    protected Log log;
    public LogDecorator(Log log) { this.log = log; }
    @Override public void debug(String message) { log.debug(message); }
    @Override public void info(String message) { log.info(message); }
    @Override public void warn(String message) { log.warn(message); }
    @Override public void error(String message) { log.error(message); }
}
public class MailLogDecorator extends LogDecorator {
    public MailLogDecorator(Log log) { super(log); }
    @Override public void warn(String message) { log.warn(message); mail(message); }
    @Override public void error(String message) { log.error(message); mail(message); }
    public void mail(String message) { log.info("邮件已发送,信息:" + message); }
}
public class SMSLogDecorator extends LogDecorator {
    public SMSLogDecorator(Log log) { super(log); }
    @Override public void error(String message) { log.error(message); send(message); }
    public void send(String message) { log.info("短信已发送,信息:" + message); }
}
public class InfoflowLogDecorator extends LogDecorator {
    public InfoflowLogDecorator(Log log) { super(log); }
    @Override public void warn(String message) { log.warn(message); send(message); }
    @Override public void error(String message) { log.error(message); send(message); }
    public void send(String message) { log.info("如流消息已发送,信息:" + message); }
}
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 连接错误");
    }
}

All three examples illustrate how the Decorator Pattern adheres to the Open/Closed Principle, enabling flexible feature extension without altering existing classes.

The article concludes that the Decorator Pattern is a powerful tool for extending functionality while keeping code maintainable.

design patternsJavasoftware architectureDecorator Patternobject-oriented
Architecture Digest
Written by

Architecture Digest

Focusing on Java backend development, covering application architecture from top-tier internet companies (high availability, high performance, high stability), big data, machine learning, Java architecture, and other popular fields.

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.