Fundamentals 11 min read

How to Refactor Course Display Logic with the Decorator Pattern in Java

This article demonstrates how to identify long‑method and duplicated code smells in a Java curriculum‑display service and refactor the implementation using the Decorator pattern, providing clear component diagrams, full code examples, and a runnable demo that showcases flexible extensions for different course types.

Senior Tony
Senior Tony
Senior Tony
How to Refactor Course Display Logic with the Decorator Pattern in Java

Business Background

A large online education platform needs to display a list of courses for students, allowing them to enter a classroom, view courseware, pre‑study material, and post‑class assignments. Different course types (English PC, English iPad, Math, Drawing) require additional information such as teacher scores, labels, or completion gifts.

Course list UI
Course list UI

Code Quality Problems

The initial implementation places all display logic inside a single query() method across four concrete classes, leading to two classic "Bad Smells" from Martin Fowler's *Refactoring*: overly long methods and duplicated code. Additionally, the classes suffer from "divergent change" because any change to course display (e.g., adding a new feature) forces modifications to every class, violating the Single Responsibility Principle.

Decorator Pattern Overview

The Decorator pattern enables adding responsibilities to objects dynamically without altering their structure, adhering to the Open/Closed Principle. Each additional feature (score, label, gift) is implemented as a separate decorator, keeping responsibilities isolated.

Dynamic addition of responsibilities without modifying existing code, improving flexibility and extensibility.

Each responsibility is a standalone decorator, eliminating long methods, duplicated code, and divergent change.

Decorator class diagram
Decorator class diagram

Component

public interface Curriculum {
    void query(int studentID);
}

ConcreteComponent

public class ConcreteCurriculum implements Curriculum {
    public void query(int studentID) {
        System.out.println("展示课表");
        System.out.println("展示对应的课前预习");
        System.out.println("展示对应的课后作业");
        System.out.println("展示对应的课件");
    }
}

Abstract Decorator

public abstract class CurriculumDecorator implements Curriculum {
    protected Curriculum curriculum;
    public CurriculumDecorator(Curriculum curriculum) {
        this.curriculum = curriculum;
    }
    public void query(int studentID) {
        curriculum.query(studentID);
    }
}

Concrete Decorators

ScoreDecorator adds student score display:

public class ScoreDecorator extends CurriculumDecorator {
    public ScoreDecorator(Curriculum curriculum) { super(curriculum); }
    @Override
    public void query(int studentID) {
        super.query(studentID);
        System.out.println("展示对应的学生评分");
    }
}

LabelDecorator adds teacher label display:

public class LabelDecorator extends CurriculumDecorator {
    public LabelDecorator(Curriculum curriculum) { super(curriculum); }
    @Override
    public void query(int studentID) {
        super.query(studentID);
        System.out.println("展示对应的老师标签");
    }
}

GiftDecorator adds completion‑gift display:

public class GiftDecorator extends CurriculumDecorator {
    public GiftDecorator(Curriculum curriculum) { super(curriculum); }
    @Override
    public void query(int studentID) {
        super.query(studentID);
        System.out.println("展示对应的完课奖品");
    }
}

Demo

public class Demo {
    public static void main(String[] args) {
        Curriculum base = new ConcreteCurriculum();
        Curriculum score = new ScoreDecorator(new ConcreteCurriculum());
        Curriculum label = new LabelDecorator(new ConcreteCurriculum());
        Curriculum gift = new GiftDecorator(label);

        System.out.println("英语PC端课表展示");
        base.query(123);
        System.out.println();

        System.out.println("英语iPad端课表展示");
        score.query(123);
        System.out.println();

        System.out.println("数学课表展示");
        label.query(123);
        System.out.println();

        System.out.println("绘画课表展示");
        gift.query(123);
    }
}

Execution Result

英语PC端课表展示
展示课表
展示对应的课前预习
展示对应的课后作业
展示对应的课件

英语iPad端课表展示
展示课表
展示对应的课前预习
展示对应的课后作业
展示对应的课件
展示对应的学生评分

数学课表展示
展示课表
展示对应的课前预习
展示对应的课后作业
展示对应的课件
展示对应的老师标签

绘画课表展示
展示课表
展示对应的课前预习
展示对应的课后作业
展示对应的课件
展示对应的老师标签
展示对应的完课奖品

Discussion

The refactored design eliminates the long‑method and duplicated‑code smells and isolates each varying requirement into its own decorator, making future extensions (e.g., adding a supplemental‑material feature for Math and Drawing only) straightforward without altering existing classes. Inheritance would require a combinatorial explosion of subclasses, whereas the decorator composition remains flexible and reusable.

design-patternsJavasoftware architecturerefactoringDecorator PatternBad Smell
Senior Tony
Written by

Senior Tony

Former senior tech manager at Meituan, ex‑tech director at New Oriental, with experience at JD.com and Qunar; specializes in Java interview coaching and regularly shares hardcore technical content. Runs a video channel of the same name.

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.