04 - Composite and Bridge Pattern: Hierarchies and Separation | Federico Calò
04 - Composite and Bridge Pattern: Hierarchies and Separation | Federico Calò
Skip to main content Home Hi! I'm
I create modern web applications and custom digital tools to help businesses grow through technological innovation. My passion is combining computer science and economics to generate real value.
My passion for computer science was born at the Technical Commercial Institute of Maglie , where I discovered the power of programming and the fascination of creating digital solutions. From the start, I understood that computer science was not just code, but an extraordinary tool for turning ideas into reality.
During my studies in Business Information Systems , I began to interweave computer science and economics, understanding how technology can be the engine of growth for any business. This vision accompanied me to the University of Bari , where I obtained my degree in Computer Science, deepening my technical skills and passion for software development.
Today I put this experience at the service of businesses, professionals and startups, creating tailor-made digital solutions that automate processes, optimize resources and open new business opportunities. Because true innovation begins when technology meets the real needs of people.
Credo fermamente che l'informatica sia lo strumento più potente per trasformare le idee in realtà e migliorare la vita delle persone.
Democratizzare la Tecnologia La mia missione è rendere l'informatica accessibile a tutti : dalle piccole imprese locali alle startup innovative, fino ai professionisti che vogliono digitalizzare la propria attività. Ogni realtà merita di sfruttare le potenzialità del digitale.
Unire Informatica ed Economia Non è solo questione di scrivere codice: è capire come la tecnologia possa generare valore reale . Intrecciando competenze informatiche e visione economica, aiuto le attività a crescere, ottimizzare processi e raggiungere nuovi traguardi di efficienza e redditività.
Creare Soluzioni su Misura Ogni attività è unica, e così devono esserlo le soluzioni. Sviluppo strumenti personalizzati che rispondono alle esigenze specifiche di ciascun cliente, automatizzando processi ripetitivi e liberando tempo per ciò che conta davvero: far crescere il business.
Trasforma la Tua Attività con la Tecnologia Che tu gestisca un negozio, uno studio professionale o un'azienda, posso aiutarti a sfruttare le potenzialità dell'informatica per lavorare meglio, più velocemente e in modo più intelligente.
Parliamone Insieme → All 8 Anthropic 5 Connect 1 Oracle 1 RoadMap.sh 1 Sort by: 📅 Date (most recent) 🔤 Name A-Z 🏢 Organization
Reinvention With Agentic AI Learning Program Anthropic
December 2024 Agentic AI Fluency Anthropic
December 2024 AI Fluency for Students Anthropic
December 2024 AI Fluency: Framework and Foundations Anthropic
December 2024 Claude with the Anthropic API Anthropic
December 2024 Master SQL RoadMap.sh
November 2024 Oracle Certified Foundations Associate Oracle
October 2024 People Leadership Credential Connect
September 2024 12/2024 - Present
Custom Software Engineering Analyst Accenture
Bari, Puglia, Italy · Hybrid
Analysis and development of computer systems through the use of Java and Quarkus in Health and Public Sector. Continuous training on modern technologies for creating customized and efficient software solutions and on agents.
06/2022 - 12/2024
Software analyst and Back End Developer Associate Consultant Links Management and Technology SpA
Experience analyzing as-is software systems and ETL flows using PowerCenter. Completed Spring Boot training for developing modern and scalable backend applications. Backend developer specialized in Spring Boot, with experience in database design, analysis, development and testing of assigned tasks.
02/2021 - 10/2021
Software programmer Adesso.it (prima era WebScience srl)
Experience in AS-IS and TO-BE analysis, SEO evolutions and website evolutions to improve user performance and engagement.
2018 - 2025
Degree in Computer Science University of Bari Aldo Moro
Bachelor's degree in Computer Science, focusing on software engineering, algorithms, and modern development practices.
2013 - 2018
Diploma - Corporate Information Systems Technical Commercial Institute of Maglie
Technical diploma specializing in Business Information Systems, combining IT knowledge with business management.
AI
Composite and Bridge Pattern
Two advanced structural patterns for managing complexity. Composite treats
individual objects and compositions uniformly (tree structures), while
Bridge separates abstraction from implementation to avoid combinatorial
explosion of subclasses.
🎯 What You Will Learn
Composite pattern: part-whole tree hierarchies
Treating single objects and composites uniformly
Bridge pattern: separating abstraction from implementation
Avoiding subclass explosion with Bridge
Composite Pattern
The Composite pattern composes objects into tree structures to
represent part-whole hierarchies. It allows clients to treat individual objects
and compositions of objects uniformly.
// Component: common interface
interface FileSystemItem {{ '{' }}
getName(): string;
getSize(): number;
print(indent: string): void;
{{ '}' }}
// Leaf: elements without children
class File implements FileSystemItem {{ '{' }}
constructor(
private name: string,
private size: number
) {{ '{' }}{{ '}' }}
getName(): string {{ '{' }}
return this.name;
{{ '}' }}
getSize(): number {{ '{' }}
return this.size;
{{ '}' }}
print(indent: string = ""): void {{ '{' }}
console.log(` #123;{ '{' }}indent{{ '}' }}📄 #123;{ '{' }}this.name{{ '}' }} (#123;{ '{' }}this.size{{ '}' }}KB)`);
{{ '}' }}
{{ '}' }}
// Composite: elements with children
class Directory implements FileSystemItem {{ '{' }}
private children: FileSystemItem[] = [];
constructor(private name: string) {{ '{' }}{{ '}' }}
getName(): string {{ '{' }}
return this.name;
{{ '}' }}
add(item: FileSystemItem): void {{ '{' }}
this.children.push(item);
{{ '}' }}
remove(item: FileSystemItem): void {{ '{' }}
const index = this.children.indexOf(item);
if (index !== -1) {{ '{' }}
this.children.splice(index, 1);
{{ '}' }}
{{ '}' }}
getSize(): number {{ '{' }}
// Recursive sum of children
return this.children.reduce((total, child) => total + child.getSize(), 0);
{{ '}' }}
print(indent: string = ""): void {{ '{' }}
console.log(`#123;{ '{' }}indent{{ '}' }}📁 #123;{ '{' }}this.name{{ '}' }} (#123;{ '{' }}this.getSize(){{ '}' }}KB)`);
this.children.forEach(child => child.print(indent + " "));
{{ '}' }}
{{ '}' }}
// Usage: create a tree structure
const root = new Directory("root");
const documents = new Directory("documents");
documents.add(new File("resume.pdf", 120));
documents.add(new File("cover_letter.docx", 45));
const photos = new Directory("photos");
photos.add(new File("vacation.jpg", 2500));
photos.add(new File("family.png", 1800));
const work = new Directory("work");
work.add(new File("project.zip", 15000));
work.add(new File("notes.txt", 5));
documents.add(work); // Nested directory
root.add(documents);
root.add(photos);
root.add(new File("readme.txt", 2));
// Treat everything uniformly
root.print();
// 📁 root (19472KB)
// 📁 documents (15170KB)
// 📄 resume.pdf (120KB)
// 📄 cover_letter.docx (45KB)
// 📁 work (15005KB)
// 📄 project.zip (15000KB)
// 📄 notes.txt (5KB)
// 📁 photos (4300KB)
// 📄 vacation.jpg (2500KB)
// 📄 family.png (1800KB)
// 📄 readme.txt (2KB)
console.log(`Total size: #123;{ '{' }}root.getSize(){{ '}' }}KB`); // 19472KB
Composite with Operations
Practical example: menu system with actions:
// Component interface
interface MenuComponent {{ '{' }}
getName(): string;
execute(): void;
print(indent: string): void;
{{ '}' }}
// Leaf: single actions
class MenuItem implements MenuComponent {{ '{' }}
constructor(
private name: string,
private action: () => void
) {{ '{' }}{{ '}' }}
getName(): string {{ '{' }}
return this.name;
{{ '}' }}
execute(): void {{ '{' }}
console.log(`▶️ Executing: #123;{ '{' }}this.name{{ '}' }}`);
this.action();
{{ '}' }}
print(indent: string = ""): void {{ '{' }}
console.log(`#123;{ '{' }}indent{{ '}' }}• #123;{ '{' }}this.name{{ '}' }}`);
{{ '}' }}
{{ '}' }}
// Composite: submenu
class Menu implements MenuComponent {{ '{' }}
private items: MenuComponent[] = [];
constructor(private name: string) {{ '{' }}{{ '}' }}
getName(): string {{ '{' }}
return this.name;
{{ '}' }}
add(item: MenuComponent): void {{ '{' }}
this.items.push(item);
{{ '}' }}
execute(): void {{ '{' }}
console.log(`📂 Opening menu: #123;{ '{' }}this.name{{ '}' }}`);
this.items.forEach(item => item.execute());
{{ '}' }}
print(indent: string = ""): void {{ '{' }}
console.log(`#123;{ '{' }}indent{{ '}' }}📂 #123;{ '{' }}this.name{{ '}' }}`);
this.items.forEach(item => item.print(indent + " "));
{{ '}' }}
{{ '}' }}
// Build hierarchical menu
const mainMenu = new Menu("Main Menu");
const fileMenu = new Menu("File");
fileMenu.add(new MenuItem("New", () => console.log("Creating new file...")));
fileMenu.add(new MenuItem("Open", () => console.log("Opening file...")));
fileMenu.add(new MenuItem("Save", () => console.log("Saving file...")));
fileMenu.add(new MenuItem("Exit", () => console.log("Exiting...")));
const editMenu = new Menu("Edit");
editMenu.add(new MenuItem("Cut", () => console.log("Cutting...")));
editMenu.add(new MenuItem("Copy", () => console.log("Copying...")));
editMenu.add(new MenuItem("Paste", () => console.log("Pasting...")));
const formatMenu = new Menu("Format");
formatMenu.add(new MenuItem("Bold", () => console.log("Applying bold...")));
formatMenu.add(new MenuItem("Italic", () => console.log("Applying italic...")));
editMenu.add(formatMenu); // Nested submenu
mainMenu.add(fileMenu);
mainMenu.add(editMenu);
// Display structure
mainMenu.print();
// 📂 Main Menu
// 📂 File
// • New
// • Open
// • Save
// • Exit
// 📂 Edit
// • Cut
// • Copy
// • Paste
// 📂 Format
// • Bold
// • Italic
// Execute all
fileMenu.execute();
// 📂 Opening menu: File
// ▶️ Executing: New
// Creating new file...
// ▶️ Executing: Open
// Opening file...
// ▶️ Executing: Save
// Saving file...
// ▶️ Executing: Exit
// Exiting...
Composite for UI Components
Realistic example: nested UI components (like React/Angular):
// Component interface
interface UIComponent {{ '{' }}
render(): string;
addClass(className: string): void;
{{ '}' }}
// Leaf: base elements
class Button implements UIComponent {{ '{' }}
private classes: string[] = [];
constructor(private text: string) {{ '{' }}{{ '}' }}
addClass(className: string): void {{ '{' }}
this.classes.push(className);
{{ '}' }}
render(): string {{ '{' }}
const classAttr = this.classes.length > 0 ? ` class="#123;{ '{' }}this.classes.join(' '){{ '}' }}"` : '';
return `<button#123;{ '{' }}classAttr{{ '}' }}>#123;{ '{' }}this.text{{ '}' }}</button>`;
{{ '}' }}
{{ '}' }}
class Input implements UIComponent {{ '{' }}
private classes: string[] = [];
constructor(
private placeholder: string,
private type: string = "text"
) {{ '{' }}{{ '}' }}
addClass(className: string): void {{ '{' }}
this.classes.push(className);
{{ '}' }}
render(): string {{ '{' }}
const classAttr = this.classes.length > 0 ? ` class="#123;{ '{' }}this.classes.join(' '){{ '}' }}"` : '';
return `<input type="#123;{ '{' }}this.type{{ '}' }}" placeholder="#123;{ '{' }}this.placeholder{{ '}' }}"#123;{ '{' }}classAttr{{ '}' }} />`;
{{ '}' }}
{{ '}' }}
// Composite: container
class Panel implements UIComponent {{ '{' }}
private children: UIComponent[] = [];
private classes: string[] = [];
constructor(private title?: string) {{ '{' }}{{ '}' }}
add(component: UIComponent): void {{ '{' }}
this.children.push(component);
{{ '}' }}
addClass(className: string): void {{ '{' }}
this.classes.push(className);
{{ '}' }}
render(): string {{ '{' }}
const classAttr = this.classes.length > 0 ? ` class="#123;{ '{' }}this.classes.join(' '){{ '}' }}"` : '';
const titleHtml = this.title ? `<h3>#123;{ '{' }}this.title{{ '}' }}</h3>` : '';
const childrenHtml = this.children.map(child => child.render()).join('\n ');
return `<div#123;{ '{' }}classAttr{{ '}' }}>
#123;{ '{' }}titleHtml{{ '}' }}
#123;{ '{' }}childrenHtml{{ '}' }}
</div>`;
{{ '}' }}
{{ '}' }}
// Build UI
const form = new Panel("Login Form");
form.addClass("card");
form.addClass("shadow");
const usernameInput = new Input("Enter username");
usernameInput.addClass("form-control");
const passwordInput = new Input("Enter password", "password");
passwordInput.addClass("form-control");
const submitButton = new Button("Login");
submitButton.addClass("btn");
submitButton.addClass("btn-primary");
form.add(usernameInput);
form.add(passwordInput);
form.add(submitButton);
console.log(form.render());
// <div class="card shadow">
// <h3>Login Form</h3>
// <input type="text" placeholder="Enter username" class="form-control" />
// <input type="password" placeholder="Enter password" class="form-control" />
// <button class="btn btn-primary">Login</button>
// </div>
Bridge Pattern
The Bridge pattern separates an abstraction from its implementation, so
that both can vary independently. It solves the combinatorial explosion of
subclasses when you have two dimensions of variability.
// Implementation: implementation interface
interface Renderer {{ '{' }}
renderCircle(radius: number): void;
renderSquare(side: number): void;
{{ '}' }}
// Concrete Implementations
class VectorRenderer implements Renderer {{ '{' }}
renderCircle(radius: number): void {{ '{' }}
console.log(`🎨 Drawing vector circle with radius #123;{ '{' }}radius{{ '}' }}`);
{{ '}' }}
renderSquare(side: number): void {{ '{' }}
console.log(`🎨 Drawing vector square with side #123;{ '{' }}side{{ '}' }}`);
{{ '}' }}
{{ '}' }}
class RasterRenderer implements Renderer {{ '{' }}
renderCircle(radius: number): void {{ '{' }}
console.log(`🖼️ Drawing raster circle (pixels) with radius #123;{ '{' }}radius{{ '}' }}`);
{{ '}' }}
renderSquare(side: number): void {{ '{' }}
console.log(`🖼️ Drawing raster square (pixels) with side #123;{ '{' }}side{{ '}' }}`);
{{ '}' }}
{{ '}' }}
// Abstraction: abstract shape
abstract class Shape {{ '{' }}
constructor(protected renderer: Renderer) {{ '{' }}{{ '}' }}
abstract draw(): void;
abstract resize(factor: number): void;
{{ '}' }}
// Refined Abstractions
class Circle extends Shape {{ '{' }}
constructor(renderer: Renderer, private radius: number) {{ '{' }}
super(renderer);
{{ '}' }}
draw(): void {{ '{' }}
this.renderer.renderCircle(this.radius);
{{ '}' }}
resize(factor: number): void {{ '{' }}
this.radius *= factor;
{{ '}' }}
{{ '}' }}
class Square extends Shape {{ '{' }}
constructor(renderer: Renderer, private side: number) {{ '{' }}
super(renderer);
{{ '}' }}
draw(): void {{ '{' }}
this.renderer.renderSquare(this.side);
{{ '}' }}
resize(factor: number): void {{ '{' }}
this.side *= factor;
{{ '}' }}
{{ '}' }}
// Usage: combine abstractions and implementations
const vectorCircle = new Circle(new VectorRenderer(), 5);
vectorCircle.draw(); // 🎨 Drawing vector circle with radius 5
const rasterCircle = new Circle(new RasterRenderer(), 5);
rasterCircle.draw(); // 🖼️ Drawing raster circle (pixels) with radius 5
const vectorSquare = new Square(new VectorRenderer(), 10);
vectorSquare.draw(); // 🎨 Drawing vector square with side 10
const rasterSquare = new Square(new RasterRenderer(), 10);
rasterSquare.draw(); // 🖼️ Drawing raster square (pixels) with side 10
// Without Bridge: you would need VectorCircle, RasterCircle, VectorSquare, RasterSquare
// With 3 shapes and 3 renderers = 9 classes!
// With Bridge: 3 shapes + 3 renderers = 6 classes
Bridge: Avoiding Subclass Explosion
Problem solved by Bridge: two dimensions of variability without combinatorial explosion:
// ❌ Approach with inheritance: class explosion
class SmallRedCircle {{ '{' }}{{ '}' }}
class SmallBlueCircle {{ '{' }}{{ '}' }}
class SmallGreenCircle {{ '{' }}{{ '}' }}
class MediumRedCircle {{ '{' }}{{ '}' }}
class MediumBlueCircle {{ '{' }}{{ '}' }}
class MediumGreenCircle {{ '{' }}{{ '}' }}
class LargeRedCircle {{ '{' }}{{ '}' }}
class LargeBlueCircle {{ '{' }}{{ '}' }}
class LargeGreenCircle {{ '{' }}{{ '}' }}
// 3 sizes x 3 colors = 9 classes just for Circle!
// Add Square, Triangle → 27 classes!
// Add one color → +9 classes!
// Implementation: colors
interface Color {{ '{' }}
fill(): string;
{{ '}' }}
class Red implements Color {{ '{' }}
fill(): string {{ '{' }} return "red"; {{ '}' }}
{{ '}' }}
class Blue implements Color {{ '{' }}
fill(): string {{ '{' }} return "blue"; {{ '}' }}
{{ '}' }}
class Green implements Color {{ '{' }}
fill(): string {{ '{' }} return "green"; {{ '}' }}
{{ '}' }}
// Abstraction: shapes with size
abstract class ColoredShape {{ '{' }}
constructor(protected color: Color) {{ '{' }}{{ '}' }}
abstract draw(): void;
{{ '}' }}
class ColoredCircle extends ColoredShape {{ '{' }}
constructor(color: Color, private size: string) {{ '{' }}
super(color);
{{ '}' }}
draw(): void {{ '{' }}
console.log(`🔴 Drawing #123;{ '{' }}this.size{{ '}' }} circle with #123;{ '{' }}this.color.fill(){{ '}' }} color`);
{{ '}' }}
{{ '}' }}
class ColoredSquare extends ColoredShape {{ '{' }}
constructor(color: Color, private size: string) {{ '{' }}
super(color);
{{ '}' }}
draw(): void {{ '{' }}
console.log(`🟦 Drawing #123;{ '{' }}this.size{{ '}' }} square with #123;{ '{' }}this.color.fill(){{ '}' }} color`);
{{ '}' }}
{{ '}' }}
// Usage: combine freely
new ColoredCircle(new Red(), "small").draw();
// 🔴 Drawing small circle with red color
new ColoredCircle(new Blue(), "large").draw();
// 🔴 Drawing large circle with blue color
new ColoredSquare(new Green(), "medium").draw();
// 🟦 Drawing medium square with green color
// 2 shapes + 3 colors = 5 classes (vs 6 with inheritance)
// Add 1 color → +1 class (vs +2)
// Scales linearly!
Bridge for Cross-Platform UI
Practical example: UI that works across different platforms:
// Implementation: platforms
interface Platform {{ '{' }}
showDialog(title: string, message: string): void;
showNotification(message: string): void;
{{ '}' }}
class WindowsPlatform implements Platform {{ '{' }}
showDialog(title: string, message: string): void {{ '{' }}
console.log(`🪟 Windows Dialog: [#123;{ '{' }}title{{ '}' }}] #123;{ '{' }}message{{ '}' }}`);
{{ '}' }}
showNotification(message: string): void {{ '{' }}
console.log(`🪟 Windows Notification: #123;{ '{' }}message{{ '}' }}`);
{{ '}' }}
{{ '}' }}
class MacOSPlatform implements Platform {{ '{' }}
showDialog(title: string, message: string): void {{ '{' }}
console.log(`🍎 macOS Alert: [#123;{ '{' }}title{{ '}' }}] #123;{ '{' }}message{{ '}' }}`);
{{ '}' }}
showNotification(message: string): void {{ '{' }}
console.log(`🍎 macOS Banner: #123;{ '{' }}message{{ '}' }}`);
{{ '}' }}
{{ '}' }}
class LinuxPlatform implements Platform {{ '{' }}
showDialog(title: string, message: string): void {{ '{' }}
console.log(`🐧 Linux Dialog: [#123;{ '{' }}title{{ '}' }}] #123;{ '{' }}message{{ '}' }}`);
{{ '}' }}
showNotification(message: string): void {{ '{' }}
console.log(`🐧 Linux Notify: #123;{ '{' }}message{{ '}' }}`);
{{ '}' }}
{{ '}' }}
// Abstraction: application
abstract class Application {{ '{' }}
constructor(protected platform: Platform) {{ '{' }}{{ '}' }}
abstract run(): void;
{{ '}' }}
class MessageApp extends Application {{ '{' }}
run(): void {{ '{' }}
this.platform.showDialog("New Message", "You have 5 new messages");
this.platform.showNotification("Message received!");
{{ '}' }}
{{ '}' }}
class SettingsApp extends Application {{ '{' }}
run(): void {{ '{' }}
this.platform.showDialog("Settings", "Configure your preferences");
{{ '}' }}
{{ '}' }}
// Usage: same app on different platforms
console.log("--- Windows ---");
const windowsMsg = new MessageApp(new WindowsPlatform());
windowsMsg.run();
// 🪟 Windows Dialog: [New Message] You have 5 new messages
// 🪟 Windows Notification: Message received!
console.log("\n--- macOS ---");
const macMsg = new MessageApp(new MacOSPlatform());
macMsg.run();
// 🍎 macOS Alert: [New Message] You have 5 new messages
// 🍎 macOS Banner: Message received!
console.log("\n--- Linux ---");
const linuxSettings = new SettingsApp(new LinuxPlatform());
linuxSettings.run();
// 🐧 Linux Dialog: [Settings] Configure your preferences
When to Use Each Pattern
✅ Use Composite when:
You want to represent part-whole hierarchies (trees)
Clients must treat single objects and compositions uniformly
Recursive structures: file systems, menus, UI components
Operations must propagate through the hierarchy
✅ Use Bridge when:
You have two independent dimensions of variability
You want to avoid combinatorial explosion of subclasses
Abstraction and implementation must vary independently
Cross-platform development, rendering engines, database drivers
Composite and Bridge Combined
// BRIDGE: separate document from storage
interface DocumentStorage {{ '{' }}
save(content: string): void;
load(): string;
{{ '}' }}
class LocalFileStorage implements DocumentStorage {{ '{' }}
save(content: string): void {{ '{' }}
console.log(`💾 Saving to local file: #123;{ '{' }}content.substring(0, 30){{ '}' }}...`);
{{ '}' }}
load(): string {{ '{' }}
return "Loaded from local file";
{{ '}' }}
{{ '}' }}
class CloudStorage implements DocumentStorage {{ '{' }}
save(content: string): void {{ '{' }}
console.log(`☁️ Uploading to cloud: #123;{ '{' }}content.substring(0, 30){{ '}' }}...`);
{{ '}' }}
load(): string {{ '{' }}
return "Loaded from cloud";
{{ '}' }}
{{ '}' }}
// COMPOSITE: document structure
interface DocumentElement {{ '{' }}
render(): string;
{{ '}' }}
class Paragraph implements DocumentElement {{ '{' }}
constructor(private text: string) {{ '{' }}{{ '}' }}
render(): string {{ '{' }}
return `<p>#123;{ '{' }}this.text{{ '}' }}</p>`;
{{ '}' }}
{{ '}' }}
class Heading implements DocumentElement {{ '{' }}
constructor(
private text: string,
private level: number
) {{ '{' }}{{ '}' }}
render(): string {{ '{' }}
return `<h#123;{ '{' }}this.level{{ '}' }}>#123;{ '{' }}this.text{{ '}' }}</h#123;{ '{' }}this.level{{ '}' }}>`;
{{ '}' }}
{{ '}' }}
class Section implements DocumentElement {{ '{' }}
private elements: DocumentElement[] = [];
add(element: DocumentElement): void {{ '{' }}
this.elements.push(element);
{{ '}' }}
render(): string {{ '{' }}
const content = this.elements.map(e => e.render()).join('\n');
return `<section>\n#123;{ '{' }}content{{ '}' }}\n</section>`;
{{ '}' }}
{{ '}' }}
// Document with Bridge for storage
class Document {{ '{' }}
private root = new Section();
constructor(private storage: DocumentStorage) {{ '{' }}{{ '}' }}
add(element: DocumentElement): void {{ '{' }}
this.root.add(element);
{{ '}' }}
save(): void {{ '{' }}
const content = this.root.render();
this.storage.save(content);
{{ '}' }}
load(): void {{ '{' }}
const content = this.storage.load();
console.log(`📄 Document loaded: #123;{ '{' }}content{{ '}' }}`);
{{ '}' }}
{{ '}' }}
// Combined usage
const localDoc = new Document(new LocalFileStorage());
localDoc.add(new Heading("Introduction", 1));
localDoc.add(new Paragraph("This is the introduction paragraph."));
localDoc.add(new Heading("Details", 2));
localDoc.add(new Paragraph("Here are the details."));
localDoc.save();
// 💾 Saving to local file: <section>
// <h1>Introduction</h1>
// <p>Thi...
const cloudDoc = new Document(new CloudStorage());
cloudDoc.add(new Heading("Cloud Document", 1));
cloudDoc.add(new Paragraph("Stored in the cloud."));
cloudDoc.save();
// ☁️ Uploading to cloud: <section>
// <h1>Cloud Document</h1>
// <p>St...
Conclusion
Composite and Bridge solve complex structural problems. Composite
unifies single objects and compositions for recursive tree structures, while
Bridge separates abstraction from implementation to avoid combinatorial
explosions. Use them for scalable and maintainable architectures.
🎯 Key Takeaways
Composite = tree hierarchies, treat leaf and composite uniformly
Use Composite for file systems, menus, UI trees
Bridge = separate abstraction from implementation
Bridge avoids N x M subclasses (becomes N + M classes)
Use Bridge for cross-platform, multi-renderer, multi-database
Both favor composition over inheritance