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.
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.
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.
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.
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.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
