Sync Composite to Java 25: H6 file labels, fix console output typo, README mapping
This commit is contained in:
@@ -1,53 +1,39 @@
|
|||||||
package composite;
|
package composite;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Composite — a directory that can hold both Files (leaves)
|
* Composite — a directory that holds both Files (leaves) and other Directories.
|
||||||
* and other Directories (composites).
|
*
|
||||||
|
* getSize() is recursive: asks each child for its size and sums them.
|
||||||
|
* print() recurses with deeper indentation.
|
||||||
*
|
*
|
||||||
* getSize() is recursive: it asks each child for its size and sums them.
|
|
||||||
* The caller doesn't care whether a child is a File or Directory —
|
* The caller doesn't care whether a child is a File or Directory —
|
||||||
* both implement FileSystemItem and answer getSize().
|
* both answer getSize() and print() the same way.
|
||||||
*
|
|
||||||
* This is the power of Composite: uniform treatment of simple and complex.
|
|
||||||
*/
|
*/
|
||||||
public class Directory implements FileSystemItem {
|
public class Directory implements FileSystemItem {
|
||||||
|
|
||||||
private final String name;
|
private final String name;
|
||||||
private final List<FileSystemItem> children = new ArrayList<>();
|
private final List<FileSystemItem> children = new ArrayList<>();
|
||||||
|
public Directory(String name) { this.name = name; }
|
||||||
public Directory(String name) {
|
// Fluent add() — allows chaining: dir.add(file1).add(file2).add(subDir)
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Directory add(FileSystemItem item) {
|
public Directory add(FileSystemItem item) {
|
||||||
children.add(item);
|
children.add(item);
|
||||||
return this; // fluent API for easy nesting
|
return this;
|
||||||
}
|
}
|
||||||
|
public void remove(FileSystemItem item) { children.remove(item); }
|
||||||
public void remove(FileSystemItem item) {
|
@Override public String getName() { return name; }
|
||||||
children.remove(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getName() { return name; }
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getSize() {
|
public long getSize() {
|
||||||
// Recursion: each child knows its own size.
|
// Each child knows its own size: files return bytes, directories recurse.
|
||||||
// Files return their bytes; directories sum their children.
|
// This is the Composite's core: uniform delegation down the tree.
|
||||||
return children.stream()
|
return children.stream()
|
||||||
.mapToLong(FileSystemItem::getSize)
|
.mapToLong(FileSystemItem::getSize)
|
||||||
.sum();
|
.sum();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void print(String indent) {
|
public void print(String indent) {
|
||||||
System.out.printf("%s[DIR] %s/ (%,d bytes total)%n", indent, name, getSize());
|
System.out.printf("%s[DIR] %s/ (%,d bytes total)%n", indent, name, getSize());
|
||||||
for (FileSystemItem child : children) {
|
for (FileSystemItem child : children) {
|
||||||
child.print(indent + " "); // recurse with deeper indent
|
child.print(indent + " "); // each level indents 4 more spaces
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,25 +1,18 @@
|
|||||||
package composite;
|
package composite;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Leaf — a single file. It has no children.
|
* Leaf — a single file with no children.
|
||||||
* getSize() returns its own size. print() shows its name.
|
* getSize() returns its own bytes. print() outputs a single line.
|
||||||
*
|
* No knowledge of directories or nesting exists in this class.
|
||||||
* Notice: the File has no knowledge of directories or nesting.
|
|
||||||
* It just knows its own name and size.
|
|
||||||
*/
|
*/
|
||||||
public class File implements FileSystemItem {
|
public class File implements FileSystemItem {
|
||||||
|
|
||||||
private final String name;
|
private final String name;
|
||||||
private final long size;
|
private final long size;
|
||||||
|
|
||||||
public File(String name, long sizeBytes) {
|
public File(String name, long sizeBytes) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.size = sizeBytes;
|
this.size = sizeBytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public String getName() { return name; }
|
@Override public String getName() { return name; }
|
||||||
@Override public long getSize() { return size; }
|
@Override public long getSize() { return size; }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void print(String indent) {
|
public void print(String indent) {
|
||||||
System.out.printf("%s[FILE] %s (%,d bytes)%n", indent, name, size);
|
System.out.printf("%s[FILE] %s (%,d bytes)%n", indent, name, size);
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
package composite;
|
package composite;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component interface — the common contract for BOTH files (leaves)
|
* Component — the common interface for both files (leaves) and directories (composites).
|
||||||
* and directories (composites). Clients work through this interface
|
* Clients work through this interface and never need to know which type they're dealing with.
|
||||||
* and never need to know which they're dealing with.
|
|
||||||
*/
|
*/
|
||||||
public interface FileSystemItem {
|
public interface FileSystemItem {
|
||||||
String getName();
|
String getName();
|
||||||
long getSize(); // total size in bytes (recursive for directories)
|
long getSize(); // total size in bytes — recursive for directories
|
||||||
void print(String indent); // display the tree
|
void print(String indent); // display the tree at the given indentation level
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,58 +1,36 @@
|
|||||||
package composite;
|
package composite;
|
||||||
|
|
||||||
/**
|
|
||||||
* Composite Design Pattern — Runnable Demo
|
|
||||||
*
|
|
||||||
* Builds a file system tree with nested directories and files.
|
|
||||||
* Demonstrates that getSize() and print() work uniformly on
|
|
||||||
* leaves (File) and composites (Directory) without any instanceof checks.
|
|
||||||
*
|
|
||||||
* Run: javac composite/*.java && java composite.Main
|
|
||||||
* Article: https://ankurm.com/composite-design-pattern-java/
|
|
||||||
*/
|
|
||||||
public class Main {
|
public class Main {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
System.out.println("=== Composite Design Pattern Demo ===\n");
|
System.out.println("=== Composite Design Pattern Demo ===\n");
|
||||||
|
// Build the tree — mix files and directories freely
|
||||||
// Build a file system tree
|
|
||||||
Directory root = new Directory("project");
|
Directory root = new Directory("project");
|
||||||
|
|
||||||
Directory src = new Directory("src");
|
Directory src = new Directory("src");
|
||||||
Directory main = new Directory("main");
|
Directory main = new Directory("main");
|
||||||
main.add(new File("App.java", 4_200))
|
main.add(new File("App.java", 4_200))
|
||||||
.add(new File("Config.java", 1_800))
|
.add(new File("Config.java", 1_800))
|
||||||
.add(new File("Application.yml", 3_100));
|
.add(new File("Application.yml", 3_100));
|
||||||
|
|
||||||
Directory test = new Directory("test");
|
Directory test = new Directory("test");
|
||||||
test.add(new File("AppTest.java", 2_600))
|
test.add(new File("AppTest.java", 2_600))
|
||||||
.add(new File("ConfigTest.java", 1_200));
|
.add(new File("ConfigTest.java", 1_200));
|
||||||
|
|
||||||
src.add(main).add(test);
|
src.add(main).add(test);
|
||||||
|
|
||||||
Directory resources = new Directory("resources");
|
Directory resources = new Directory("resources");
|
||||||
resources.add(new File("application.yml", 1_500))
|
resources.add(new File("application.yml", 1_500))
|
||||||
.add(new File("logback.xml", 900))
|
.add(new File("logback.xml", 900))
|
||||||
.add(new File("banner.txt", 200));
|
.add(new File("banner.txt", 200));
|
||||||
|
|
||||||
root.add(src)
|
root.add(src)
|
||||||
.add(resources)
|
.add(resources)
|
||||||
.add(new File("pom.xml", 8_400))
|
.add(new File("pom.xml", 8_400))
|
||||||
.add(new File("README.md", 2_100));
|
.add(new File("README.md", 2_100));
|
||||||
|
// Print the entire tree — recursion is automatic
|
||||||
// Print entire tree — recursion happens automatically
|
|
||||||
System.out.println("File system tree:");
|
System.out.println("File system tree:");
|
||||||
root.print("");
|
root.print("");
|
||||||
|
|
||||||
System.out.printf("%nTotal project size: %,d bytes%n", root.getSize());
|
System.out.printf("%nTotal project size: %,d bytes%n", root.getSize());
|
||||||
|
// The key demonstration: File and Directory through the same interface
|
||||||
// Client treats File and Directory identically
|
|
||||||
System.out.println("\n-- Treating File and Directory uniformly --");
|
System.out.println("\n-- Treating File and Directory uniformly --");
|
||||||
FileSystemItem[] items = { new File("standalone.txt", 500), src };
|
FileSystemItem[] items = { new File("standalone.txt", 500), src };
|
||||||
for (FileSystemItem item : items) {
|
for (FileSystemItem item : items) {
|
||||||
System.out.printf("%s -> size: %,d bytes%n", item.getName(), item.getSize());
|
System.out.printf("%s -> size: %,d bytes%n", item.getName(), item.getSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
System.out.println("\n=== Demo complete ===");
|
System.out.println("\n=== Demo complete ===");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
30
02-structural/composite/README.md
Normal file
30
02-structural/composite/README.md
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
# Composite Design Pattern — Java Example
|
||||||
|
|
||||||
|
**Pattern:** Structural → Composite
|
||||||
|
**Article:** https://ankurm.com/composite-design-pattern-java/
|
||||||
|
|
||||||
|
## What this example shows
|
||||||
|
|
||||||
|
Builds a file system tree where files (leaves) and directories (composites) share the same `FileSystemItem` interface. Callers compute size or print the tree without ever checking whether a node is a file or a directory.
|
||||||
|
|
||||||
|
## How to run
|
||||||
|
|
||||||
|
```bash
|
||||||
|
javac composite/*.java -d out/composite
|
||||||
|
java -cp out/composite composite.Main
|
||||||
|
```
|
||||||
|
|
||||||
|
Requires Java 25.
|
||||||
|
|
||||||
|
## Post Section ↔ File Mapping
|
||||||
|
|
||||||
|
| Post Section | File(s) |
|
||||||
|
|---|---|
|
||||||
|
| The Problem: Treating Leaves and Containers Uniformly | illustrative only — not part of this repository's runnable example |
|
||||||
|
| Step 1 — The Component Interface | `FileSystemItem.java` |
|
||||||
|
| Step 2 — The Leaf (File) | `File.java` |
|
||||||
|
| Step 3 — The Composite (Directory) | `Directory.java` |
|
||||||
|
| Building and Using the Tree | `Main.java` |
|
||||||
|
|
||||||
|
Article: https://ankurm.com/composite-design-pattern-java/
|
||||||
|
All patterns: https://ankurm.com/design-patterns-java/
|
||||||
16
README.md
16
README.md
@@ -215,6 +215,22 @@ javac 02-structural/bridge/*.java -d out/bridge
|
|||||||
java -cp out/bridge bridge.Main
|
java -cp out/bridge bridge.Main
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Composite (`02-structural/composite/`)
|
||||||
|
|
||||||
|
| Post Section | File(s) |
|
||||||
|
|---|---|
|
||||||
|
| The Problem: Treating Leaves and Containers Uniformly | illustrative only — not part of this repository's runnable example |
|
||||||
|
| Step 1 — The Component Interface | `FileSystemItem.java` |
|
||||||
|
| Step 2 — The Leaf (File) | `File.java` |
|
||||||
|
| Step 3 — The Composite (Directory) | `Directory.java` |
|
||||||
|
| Building and Using the Tree | `Main.java` |
|
||||||
|
|
||||||
|
Run it:
|
||||||
|
```bash
|
||||||
|
javac 02-structural/composite/*.java -d out/composite
|
||||||
|
java -cp out/composite composite.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
|
||||||
|
|||||||
Reference in New Issue
Block a user