1. The Hook (The "Byte-Sized" Intro)
- In a Nutshell: Bridge = decouple abstraction from implementation (remote control + device), Composite = tree structure, treat leaf & composite uniformly (file system: files + folders), Flyweight = share objects to save memory (String pool, chess pieces).
- Benefits: Flexibility (Bridge), uniform treatment (Composite), memory efficiency (Flyweight).
- Use: Bridge for platform independence, Composite for part-whole hierarchies, Flyweight for many similar objects!
Bridge = universal remote (one remote, many devices). Composite = company org chart (CEO → managers → employees, all are "Employee"). Flyweight = concert tickets (shared venue info, unique seat number)!
2. Conceptual Clarity (The "Simple" Tier)
💡 The Analogy
- Bridge: Car + driver (separate concerns)
- Composite: Russian nesting dolls (container + items)
- Flyweight: Library books (share content, unique borrower card)
3. Technical Mastery (The "Deep Dive")
java
// ===========================================
// 1. BRIDGE PATTERN
// ===========================================
// Implementation
interface Device {
void turnOn();
void turnOff();
}
class TV implements Device {
public void turnOn() { System.out.println("TV on"); }
public void turnOff() { System.out.println("TV off"); }
}
class Radio implements Device {
public void turnOn() { System.out.println("Radio on"); }
public void turnOff() { System.out.println("Radio off"); }
}
// Abstraction
abstract class RemoteControl {
protected Device device;
RemoteControl(Device device) {
this.device = device;
}
abstract void togglePower();
}
class BasicRemote extends RemoteControl {
BasicRemote(Device device) {
super(device);
}
void togglePower() {
device.turnOn();
device.turnOff();
}
}
// Usage: Mix and match!
RemoteControl remote1 = new BasicRemote(new TV());
RemoteControl remote2 = new BasicRemote(new Radio());
// ===========================================
// 2. COMPOSITE PATTERN
// ===========================================
// Component
interface FileSystemNode {
void print(String indent);
int getSize();
}
// Leaf
class File implements FileSystemNode {
private String name;
private int size;
File(String name, int size) {
this.name = name;
this.size = size;
}
public void print(String indent) {
System.out.println(indent + name + " (" + size + " bytes)");
}
public int getSize() {
return size;
}
}
// Composite
class Folder implements FileSystemNode {
private String name;
private List<FileSystemNode> children = new ArrayList<>();
Folder(String name) {
this.name = name;
}
void add(FileSystemNode node) {
children.add(node);
}
public void print(String indent) {
System.out.println(indent + name + "/");
for (FileSystemNode child : children) {
child.print(indent + " ");
}
}
public int getSize() {
return children.stream()
.mapToInt(FileSystemNode::getSize)
.sum();
}
}
// Usage:
Folder root = new Folder("root");
root.add(new File("file1.txt", 100));
Folder docs = new Folder("docs");
docs.add(new File("doc1.pdf", 500));
docs.add(new File("doc2.pdf", 300));
root.add(docs);
root.print(""); // Prints tree structure
System.out.println("Total: " + root.getSize());
// ===========================================
// 3. FLYWEIGHT PATTERN
// ===========================================
// Flyweight (intrinsic state = shared)
class ChessPiece {
private final String color; // Shared
private final String type; // Shared
ChessPiece(String color, String type) {
this.color = color;
this.type = type;
}
void render(int x, int y) { // Extrinsic state = unique
System.out.println(color + " " + type + " at (" + x + "," + y + ")");
}
}
// Flyweight factory
class ChessPieceFactory {
private static Map<String, ChessPiece> pieces = new HashMap<>();
static ChessPiece getPiece(String color, String type) {
String key = color + "-" + type;
if (!pieces.containsKey(key)) {
pieces.put(key, new ChessPiece(color, type));
System.out.println("Created: " + key);
}
return pieces.get(key);
}
}
// Usage:
ChessPiece p1 = ChessPieceFactory.getPiece("White", "Pawn");
ChessPiece p2 = ChessPieceFactory.getPiece("White", "Pawn");
// p1 == p2 (same object!)
p1.render(0, 1);
p2.render(1, 1);
// Shared object, different positions!5. The Comparison & Decision Layer
| Pattern | Use When |
|---|---|
| Bridge | Vary abstraction + implementation independently |
| Composite | Part-whole hierarchy, tree structure |
| Flyweight | Many similar objects, memory optimization |
6. The "Interview Corner" (The Edge)
The "Killer" Interview Question: "Explain Flyweight with String pool." Answer: String pool is Flyweight pattern!
java
String s1 = "Hello"; // Created in pool
String s2 = "Hello"; // Reuses same object!
System.out.println(s1 == s2); // true (same reference)
// Flyweight:
// - Intrinsic state: "Hello" (shared)
// - Extrinsic state: Where it's used (unique)
// - Factory: String poolPro-Tip: Composite in UI frameworks:
java
// Swing uses Composite
JPanel panel = new JPanel(); // Composite
panel.add(new JButton("OK")); // Leaf
panel.add(new JLabel("Name")); // Leaf
JPanel nested = new JPanel(); // Another composite
nested.add(new JTextField());
panel.add(nested); // Composite in composite!
// All are Component (uniform interface)