The Composite pattern solves a classic problem:
👉 How to treat simple objects (“leaves”) and groups of objects (“composites”) in the same way?
In Traditional OOP
In OOP, we usually create:
- a Component interface,
- a Leaf class (e.g., a
File) with no children, - a Composite class (e.g., a
Folder) that contains other components.
It works, but the design often feels implicit: we must know by convention that File is a leaf and Folder is a composite.
In Clprolf
With Clprolf, roles and contracts make the Composite explicit:
-
FileSystemComponentis the contract for all components. -
Fileis a Leaf: anabstractionwith no extra methods. -
Folderis a Composite: anabstractionwithadd()/remove()methods for direct children. - Implementations (
FileImpl,FolderImpl) respect these roles withcontracts. - A
worker_agentlauncher builds the tree and callsdone().
The result: we can read the roles and hierarchy directly in the contracts — no ambiguity.
Example
public version_inh FileSystemComponent {
void done();
}
public version_inh abstraction File nature FileSystemComponent { }
public version_inh abstraction Folder nature FileSystemComponent {
void add(with_compat FileSystemComponent component);
void remove(with_compat FileSystemComponent component);
}
Leaf
@Forced_pract_code
public abstraction FileImpl contracts File {
private String name;
public FileImpl(String name) { this.name = name; }
public void done() { System.out.println("Leaf File: " + name); }
}
Composite
@Forced_pract_code
public abstraction FolderImpl contracts Folder {
private String name;
private List<FileSystemComponent> children = new ArrayList<>();
public FolderImpl(String name) { this.name = name; }
public void add(with_compat FileSystemComponent component) {
children.add(component);
}
public void remove(with_compat FileSystemComponent component) {
children.remove(component);
}
public void done() {
System.out.println("Composite Folder: " + name);
for (with_compat FileSystemComponent c : children) c.done();
}
}
Launcher
public worker_agent CompositePatternLauncher {
public static void main(String[] args) {
FolderImpl root = new FolderImpl("Root");
FolderImpl documents = new FolderImpl("Documents");
FileImpl file1 = new FileImpl("File1.txt");
documents.add(file1);
root.add(documents);
root.done();
}
}
Output
Composite Folder: Root
Composite Folder: Documents
Leaf File: File1.txt
Why Clprolf Makes Composite Clear
- Contracts show everything
-
Fileis a Leaf (no extra methods). -
Folderis a Composite (can add/remove children). - Both are
FileSystemComponent.
Each composite is simple
AFolderonly knows its direct children.
The global hierarchy comes from recursion, not from extra complexity.Roles prevent ambiguity
Implementations respect exactly the declared role — no mix-up between leaf and composite.
Conclusion
In OOP, the Composite is often taught as a trick with interfaces and polymorphism.
In Clprolf, it becomes obvious:
- A Leaf is an
abstractionwithout children. - A Composite is an
abstractionwith children of typeFileSystemComponent.
👉 The pattern is no longer something to memorize, but something you can read directly in the contracts.
Top comments (0)