Sync Decorator to Java 25: H6 file labels, fix Main.java JDK-output mismatch, README mapping

This commit is contained in:
2026-06-24 14:39:15 +05:30
parent ad6a65a95d
commit d6df1fd013
9 changed files with 79 additions and 60 deletions

View File

@@ -1,28 +1,17 @@
package decorator; 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 class Main {
public static void main(String[] args) { public static void main(String[] args) {
System.out.println("=== Decorator Design Pattern Demo ===\n"); System.out.println("=== Decorator Design Pattern Demo ===\n");
String input = " hello world, badword is here "; String input = " hello world, badword is here ";
System.out.println("Input: \"" + input + "\""); System.out.println("Input: \"" + input + "\"\n");
System.out.println();
// Stack 1: just trim // Stack 1: just trim
TextProcessor trimOnly = new TrimDecorator(new PlainTextProcessor()); TextProcessor trimOnly = new TrimDecorator(new PlainTextProcessor());
System.out.println("Trim only: \"" + trimOnly.process(input) + "\""); 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 = TextProcessor trimThenUpper =
new UpperCaseDecorator( new UpperCaseDecorator(
new TrimDecorator( new TrimDecorator(
@@ -37,15 +26,15 @@ public class Main {
new PlainTextProcessor()))); new PlainTextProcessor())));
System.out.println("Trim + Filter + Upper: \"" + full.process(input) + "\""); 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 = TextProcessor filterFirst =
new TrimDecorator( new TrimDecorator(
new ProfanityFilterDecorator( new ProfanityFilterDecorator(
new PlainTextProcessor())); new PlainTextProcessor()));
System.out.println("Filter + Trim: \"" + filterFirst.process(input) + "\""); System.out.println("Filter + Trim: \"" + filterFirst.process(input) + "\"");
System.out.println(); System.out.println("\n--- JDK equivalent ---");
System.out.println("JDK parallel: new BufferedReader(new InputStreamReader(socket.getInputStream()))"); System.out.println("new BufferedReader(new InputStreamReader(socket.getInputStream()))");
System.out.println("Same pattern: each wrapper adds one behaviour, order matters."); System.out.println("Same pattern: each wrapper adds one behaviour, order matters.");
System.out.println("\n=== Demo complete ==="); System.out.println("\n=== Demo complete ===");

View File

@@ -1,14 +1,12 @@
package decorator; package decorator;
/** /**
* Concrete Component — the base object being decorated. * Concrete Component — the starting point for decoration.
* Does nothing special: just returns the text as-is. * Returns text unchanged. Decorators wrap around this
* All decorators wrap this (or other decorators on top of it). * and transform the result one layer at a time.
*/ */
public class PlainTextProcessor implements TextProcessor { public class PlainTextProcessor implements TextProcessor {
@Override @Override
public String process(String text) { public String process(String text) {
return text; // base: no transformation return text; // no transformation — base case
} }
} }

View File

@@ -1,14 +1,8 @@
package decorator; package decorator;
/** Concrete Decorator: replaces profane words with asterisks. */
/** Concrete Decorator 3: replaces bad words with asterisks. */
public class ProfanityFilterDecorator extends TextDecorator { public class ProfanityFilterDecorator extends TextDecorator {
private static final String[] BAD_WORDS = {"badword", "spam"}; private static final String[] BAD_WORDS = {"badword", "spam"};
public ProfanityFilterDecorator(TextProcessor wrapped) { super(wrapped); }
public ProfanityFilterDecorator(TextProcessor wrapped) {
super(wrapped);
}
@Override @Override
public String process(String text) { public String process(String text) {
String result = super.process(text); String result = super.process(text);

View File

@@ -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/

View File

@@ -1,25 +1,22 @@
package decorator; package decorator;
/** /**
* Base Decorator — holds a reference to the wrapped TextProcessor. * Base Decorator — holds a reference to the wrapped TextProcessor
* All concrete decorators extend this instead of implementing * and delegates to it. Concrete decorators extend this class.
* TextProcessor directly. This avoids repeating the delegation
* boilerplate in every decorator.
* *
* Crucially: it delegates to the wrapped processor first, * Why an abstract class rather than another interface implementation?
* then applies its own transformation to the result. * To avoid repeating the wrapping boilerplate (the field + constructor +
* delegation call) in every single concrete decorator.
*/ */
public abstract class TextDecorator implements TextProcessor { public abstract class TextDecorator implements TextProcessor {
protected final TextProcessor wrapped; protected final TextProcessor wrapped;
protected TextDecorator(TextProcessor wrapped) { protected TextDecorator(TextProcessor wrapped) {
this.wrapped = wrapped; this.wrapped = wrapped;
} }
@Override @Override
public String process(String text) { 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); return wrapped.process(text);
} }
} }

View File

@@ -1,9 +1,8 @@
package decorator; package decorator;
/** /**
* Component interface — defines what all text processors do. * Component — defines what all text processors do.
* Both the concrete processor AND all decorators implement this. * Both the base implementation AND every decorator implement this.
* This is what makes them stackable. * Sharing this type is what makes decorators stackable.
*/ */
public interface TextProcessor { public interface TextProcessor {
String process(String text); String process(String text);

View File

@@ -1,12 +1,7 @@
package decorator; package decorator;
/** Concrete Decorator: trims leading and trailing whitespace. */
/** Concrete Decorator 2: trims leading/trailing whitespace. */
public class TrimDecorator extends TextDecorator { public class TrimDecorator extends TextDecorator {
public TrimDecorator(TextProcessor wrapped) { super(wrapped); }
public TrimDecorator(TextProcessor wrapped) {
super(wrapped);
}
@Override @Override
public String process(String text) { public String process(String text) {
return super.process(text).trim(); return super.process(text).trim();

View File

@@ -1,16 +1,13 @@
package decorator; package decorator;
/** Concrete Decorator: converts result to upper case. */
/** Concrete Decorator 1: converts all text to upper case. */
public class UpperCaseDecorator extends TextDecorator { public class UpperCaseDecorator extends TextDecorator {
public UpperCaseDecorator(TextProcessor wrapped) { public UpperCaseDecorator(TextProcessor wrapped) {
super(wrapped); super(wrapped);
} }
@Override @Override
public String process(String text) { public String process(String text) {
// Get the result from whatever is below us in the stack, // 1. Get result from everything below in the stack
// then apply OUR transformation on top of it. // 2. Apply OUR transformation: uppercase
return super.process(text).toUpperCase(); return super.process(text).toUpperCase();
} }
} }

View File

@@ -231,6 +231,24 @@ javac 02-structural/composite/*.java -d out/composite
java -cp out/composite composite.Main 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 ## Reference
- *Design Patterns: Elements of Reusable Object-Oriented Software* — Gamma, Helm, Johnson, Vlissides - *Design Patterns: Elements of Reusable Object-Oriented Software* — Gamma, Helm, Johnson, Vlissides