From d6df1fd0130e1c41fe71a2f1e83fb7a5cedfa35e Mon Sep 17 00:00:00 2001 From: Ankur Date: Wed, 24 Jun 2026 14:39:15 +0530 Subject: [PATCH] Sync Decorator to Java 25: H6 file labels, fix Main.java JDK-output mismatch, README mapping --- 02-structural/decorator/Main.java | 25 ++++----------- .../decorator/PlainTextProcessor.java | 10 +++--- .../decorator/ProfanityFilterDecorator.java | 10 ++---- 02-structural/decorator/README.md | 32 +++++++++++++++++++ 02-structural/decorator/TextDecorator.java | 19 +++++------ 02-structural/decorator/TextProcessor.java | 7 ++-- 02-structural/decorator/TrimDecorator.java | 9 ++---- .../decorator/UpperCaseDecorator.java | 9 ++---- README.md | 18 +++++++++++ 9 files changed, 79 insertions(+), 60 deletions(-) create mode 100644 02-structural/decorator/README.md diff --git a/02-structural/decorator/Main.java b/02-structural/decorator/Main.java index 7139696..e08d3c4 100644 --- a/02-structural/decorator/Main.java +++ b/02-structural/decorator/Main.java @@ -1,35 +1,24 @@ package decorator; - -/** - * Decorator Design Pattern — Runnable Demo - * - * Shows how text processors can be stacked like Java IO streams. - * Each decorator adds one behaviour; the order of wrapping matters. - * - * Run: javac decorator/*.java && java decorator.Main - * Article: https://ankurm.com/decorator-design-pattern-java/ - */ public class Main { - public static void main(String[] args) { System.out.println("=== Decorator Design Pattern Demo ===\n"); String input = " hello world, badword is here "; - System.out.println("Input: \"" + input + "\""); - System.out.println(); + System.out.println("Input: \"" + input + "\"\n"); // Stack 1: just trim TextProcessor trimOnly = new TrimDecorator(new PlainTextProcessor()); System.out.println("Trim only: \"" + trimOnly.process(input) + "\""); - // Stack 2: trim, then upper case + // Stack 2: trim first (innermost), then uppercase (outermost) + // Execution order: PlainText → Trim → UpperCase TextProcessor trimThenUpper = new UpperCaseDecorator( new TrimDecorator( new PlainTextProcessor())); System.out.println("Trim + UpperCase: \"" + trimThenUpper.process(input) + "\""); - // Stack 3: trim, filter profanity, then upper case + // Stack 3: trim, filter profanity, then uppercase TextProcessor full = new UpperCaseDecorator( new ProfanityFilterDecorator( @@ -37,15 +26,15 @@ public class Main { new PlainTextProcessor()))); System.out.println("Trim + Filter + Upper: \"" + full.process(input) + "\""); - // Stack 4: different order — filter then trim (order matters!) + // Stack 4: filter THEN trim — different result because order changed TextProcessor filterFirst = new TrimDecorator( new ProfanityFilterDecorator( new PlainTextProcessor())); System.out.println("Filter + Trim: \"" + filterFirst.process(input) + "\""); - System.out.println(); - System.out.println("JDK parallel: new BufferedReader(new InputStreamReader(socket.getInputStream()))"); + System.out.println("\n--- JDK equivalent ---"); + System.out.println("new BufferedReader(new InputStreamReader(socket.getInputStream()))"); System.out.println("Same pattern: each wrapper adds one behaviour, order matters."); System.out.println("\n=== Demo complete ==="); diff --git a/02-structural/decorator/PlainTextProcessor.java b/02-structural/decorator/PlainTextProcessor.java index 18bc4fd..5b99c92 100644 --- a/02-structural/decorator/PlainTextProcessor.java +++ b/02-structural/decorator/PlainTextProcessor.java @@ -1,14 +1,12 @@ package decorator; - /** - * Concrete Component — the base object being decorated. - * Does nothing special: just returns the text as-is. - * All decorators wrap this (or other decorators on top of it). + * Concrete Component — the starting point for decoration. + * Returns text unchanged. Decorators wrap around this + * and transform the result one layer at a time. */ public class PlainTextProcessor implements TextProcessor { - @Override public String process(String text) { - return text; // base: no transformation + return text; // no transformation — base case } } diff --git a/02-structural/decorator/ProfanityFilterDecorator.java b/02-structural/decorator/ProfanityFilterDecorator.java index 9b4b259..9535849 100644 --- a/02-structural/decorator/ProfanityFilterDecorator.java +++ b/02-structural/decorator/ProfanityFilterDecorator.java @@ -1,14 +1,8 @@ package decorator; - -/** Concrete Decorator 3: replaces bad words with asterisks. */ +/** Concrete Decorator: replaces profane words with asterisks. */ public class ProfanityFilterDecorator extends TextDecorator { - private static final String[] BAD_WORDS = {"badword", "spam"}; - - public ProfanityFilterDecorator(TextProcessor wrapped) { - super(wrapped); - } - + public ProfanityFilterDecorator(TextProcessor wrapped) { super(wrapped); } @Override public String process(String text) { String result = super.process(text); diff --git a/02-structural/decorator/README.md b/02-structural/decorator/README.md new file mode 100644 index 0000000..611025a --- /dev/null +++ b/02-structural/decorator/README.md @@ -0,0 +1,32 @@ +# Decorator Design Pattern — Java Example + +**Pattern:** Structural → Decorator +**Article:** https://ankurm.com/decorator-design-pattern-java/ + +## What this example shows + +Builds a text-processing pipeline where behaviours (trim, uppercase, profanity filter) are stacked as wrapper objects around a `PlainTextProcessor`, all sharing the `TextProcessor` interface — the same idea behind `new BufferedReader(new InputStreamReader(...))` in the JDK. + +## How to run + +```bash +javac decorator/*.java -d out/decorator +java -cp out/decorator decorator.Main +``` + +Requires Java 25. + +## Post Section ↔ File Mapping + +| Post Section | File(s) | +|---|---| +| Step 1 — Component Interface | `TextProcessor.java` | +| Step 2 — Concrete Component | `PlainTextProcessor.java` | +| Step 3 — Base Decorator | `TextDecorator.java` | +| Step 4 — Concrete Decorators | `UpperCaseDecorator.java`, `TrimDecorator.java`, `ProfanityFilterDecorator.java` | +| Stacking the Decorators — Order Matters | `Main.java` | + +Note: the JDK `InputStream`/`BufferedInputStream`/`GZIPInputStream` snippet under "Decorator in the JDK: I/O Streams" is illustrative only — it is not part of this repository's runnable example. + +Article: https://ankurm.com/decorator-design-pattern-java/ +All patterns: https://ankurm.com/design-patterns-java/ diff --git a/02-structural/decorator/TextDecorator.java b/02-structural/decorator/TextDecorator.java index 303b9f2..91eefa2 100644 --- a/02-structural/decorator/TextDecorator.java +++ b/02-structural/decorator/TextDecorator.java @@ -1,25 +1,22 @@ package decorator; - /** - * Base Decorator — holds a reference to the wrapped TextProcessor. - * All concrete decorators extend this instead of implementing - * TextProcessor directly. This avoids repeating the delegation - * boilerplate in every decorator. + * Base Decorator — holds a reference to the wrapped TextProcessor + * and delegates to it. Concrete decorators extend this class. * - * Crucially: it delegates to the wrapped processor first, - * then applies its own transformation to the result. + * Why an abstract class rather than another interface implementation? + * To avoid repeating the wrapping boilerplate (the field + constructor + + * delegation call) in every single concrete decorator. */ public abstract class TextDecorator implements TextProcessor { - protected final TextProcessor wrapped; - protected TextDecorator(TextProcessor wrapped) { this.wrapped = wrapped; } - @Override public String process(String text) { - // Delegate to the wrapped processor first, then let subclass apply its transform + // Default: pass through to the wrapped processor. + // Concrete decorators call super.process(text) to invoke this, + // then apply their own transformation to the result. return wrapped.process(text); } } diff --git a/02-structural/decorator/TextProcessor.java b/02-structural/decorator/TextProcessor.java index db7507f..dffff0a 100644 --- a/02-structural/decorator/TextProcessor.java +++ b/02-structural/decorator/TextProcessor.java @@ -1,9 +1,8 @@ package decorator; - /** - * Component interface — defines what all text processors do. - * Both the concrete processor AND all decorators implement this. - * This is what makes them stackable. + * Component — defines what all text processors do. + * Both the base implementation AND every decorator implement this. + * Sharing this type is what makes decorators stackable. */ public interface TextProcessor { String process(String text); diff --git a/02-structural/decorator/TrimDecorator.java b/02-structural/decorator/TrimDecorator.java index 73bbbe5..d98eda2 100644 --- a/02-structural/decorator/TrimDecorator.java +++ b/02-structural/decorator/TrimDecorator.java @@ -1,12 +1,7 @@ package decorator; - -/** Concrete Decorator 2: trims leading/trailing whitespace. */ +/** Concrete Decorator: trims leading and trailing whitespace. */ public class TrimDecorator extends TextDecorator { - - public TrimDecorator(TextProcessor wrapped) { - super(wrapped); - } - + public TrimDecorator(TextProcessor wrapped) { super(wrapped); } @Override public String process(String text) { return super.process(text).trim(); diff --git a/02-structural/decorator/UpperCaseDecorator.java b/02-structural/decorator/UpperCaseDecorator.java index 625dbeb..7f49757 100644 --- a/02-structural/decorator/UpperCaseDecorator.java +++ b/02-structural/decorator/UpperCaseDecorator.java @@ -1,16 +1,13 @@ package decorator; - -/** Concrete Decorator 1: converts all text to upper case. */ +/** Concrete Decorator: converts result to upper case. */ public class UpperCaseDecorator extends TextDecorator { - public UpperCaseDecorator(TextProcessor wrapped) { super(wrapped); } - @Override public String process(String text) { - // Get the result from whatever is below us in the stack, - // then apply OUR transformation on top of it. + // 1. Get result from everything below in the stack + // 2. Apply OUR transformation: uppercase return super.process(text).toUpperCase(); } } diff --git a/README.md b/README.md index 75b11e0..8a45a09 100644 --- a/README.md +++ b/README.md @@ -231,6 +231,24 @@ javac 02-structural/composite/*.java -d out/composite java -cp out/composite composite.Main ``` +### Decorator (`02-structural/decorator/`) + +| Post Section | File(s) | +|---|---| +| Step 1 — Component Interface | `TextProcessor.java` | +| Step 2 — Concrete Component | `PlainTextProcessor.java` | +| Step 3 — Base Decorator | `TextDecorator.java` | +| Step 4 — Concrete Decorators | `UpperCaseDecorator.java`, `TrimDecorator.java`, `ProfanityFilterDecorator.java` | +| Stacking the Decorators — Order Matters | `Main.java` | + +Note: the JDK `InputStream`/`BufferedInputStream`/`GZIPInputStream` snippet is illustrative only — it is not part of this repository's runnable example. + +Run it: +```bash +javac 02-structural/decorator/*.java -d out/decorator +java -cp out/decorator decorator.Main +``` + ## Reference - *Design Patterns: Elements of Reusable Object-Oriented Software* — Gamma, Helm, Johnson, Vlissides