Salta al contenuto principale

04 - Composite e Bridge Pattern: Gerarchie e Separazione

Composite pattern per strutture ad albero ricorsive e Bridge pattern per separare astrazione da implementazione con esempi pratici.

Cosa ne pensi di questo articolo?

04 - Composite e Bridge Pattern: Gerarchie e Separazione
Design PatternsFoto:SiddePexels

In Breve

Composite pattern per strutture ad albero ricorsive e Bridge pattern per separare astrazione da implementazione con esempi pratici.

Composite e Bridge Pattern

Due pattern strutturali avanzati per gestire complessità. Composite tratta oggetti individuali e composizioni in modo uniforme (strutture ad albero), mentre Bridge separa astrazione da implementazione per evitare esplosione combinatoria di sottoclassi.

🎯 Cosa Imparerai

  • Composite pattern: gerarchie ad albero part-whole
  • Trattare oggetti singoli e compositi uniformemente
  • Bridge pattern: separare astrazione da implementazione
  • Evitare esplosione di sottoclassi con Bridge

Composite Pattern

Il Composite pattern compone oggetti in strutture ad albero per rappresentare gerarchie part-whole. Permette ai client di trattare singoli oggetti e composizioni di oggetti in modo uniforme.

TypeScript - Composite Base
// Component: interfaccia comune
interface FileSystemItem {{ '{' }}
  getName(): string;
  getSize(): number;
  print(indent: string): void;
{{ '}' }}

// Leaf: elementi senza figli
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(`${{ '{' }}indent{{ '}' }}📄 ${{ '{' }}this.name{{ '}' }} (${{ '{' }}this.size{{ '}' }}KB)`);
  {{ '}' }}
{{ '}' }}

// Composite: elementi con figli
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 {{ '{' }}
    // Somma ricorsiva dei figli
    return this.children.reduce((total, child) => total + child.getSize(), 0);
  {{ '}' }}

  print(indent: string = ""): void {{ '{' }}
    console.log(`${{ '{' }}indent{{ '}' }}📁 ${{ '{' }}this.name{{ '}' }} (${{ '{' }}this.getSize(){{ '}' }}KB)`);
    this.children.forEach(child => child.print(indent + "  "));
  {{ '}' }}
{{ '}' }}

// Utilizzo: crea struttura ad albero
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); // Directory annidato

root.add(documents);
root.add(photos);
root.add(new File("readme.txt", 2));

// Tratta tutto uniformemente
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: ${{ '{' }}root.getSize(){{ '}' }}KB`); // 19472KB

Composite con Operazioni

Esempio pratico: sistema di menu con azioni:

Menu System Composite
// Component interface
interface MenuComponent {{ '{' }}
  getName(): string;
  execute(): void;
  print(indent: string): void;
{{ '}' }}

// Leaf: azioni singole
class MenuItem implements MenuComponent {{ '{' }}
  constructor(
    private name: string,
    private action: () => void
  ) {{ '{' }}{{ '}' }}

  getName(): string {{ '{' }}
    return this.name;
  {{ '}' }}

  execute(): void {{ '{' }}
    console.log(`▶️ Executing: ${{ '{' }}this.name{{ '}' }}`);
    this.action();
  {{ '}' }}

  print(indent: string = ""): void {{ '{' }}
    console.log(`${{ '{' }}indent{{ '}' }}• ${{ '{' }}this.name{{ '}' }}`);
  {{ '}' }}
{{ '}' }}

// Composite: sottomenu
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: ${{ '{' }}this.name{{ '}' }}`);
    this.items.forEach(item => item.execute());
  {{ '}' }}

  print(indent: string = ""): void {{ '{' }}
    console.log(`${{ '{' }}indent{{ '}' }}📂 ${{ '{' }}this.name{{ '}' }}`);
    this.items.forEach(item => item.print(indent + "  "));
  {{ '}' }}
{{ '}' }}

// Costruisci menu gerarchico
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); // Sottomenu annidato

mainMenu.add(fileMenu);
mainMenu.add(editMenu);

// Visualizza struttura
mainMenu.print();
// 📂 Main Menu
//   📂 File
//     • New
//     • Open
//     • Save
//     • Exit
//   📂 Edit
//     • Cut
//     • Copy
//     • Paste
//     📂 Format
//       • Bold
//       • Italic

// Esegui tutti
fileMenu.execute();
// 📂 Opening menu: File
// ▶️ Executing: New
// Creating new file...
// ▶️ Executing: Open
// Opening file...
// ▶️ Executing: Save
// Saving file...
// ▶️ Executing: Exit
// Exiting...

Composite per UI Components

Esempio realistico: componenti UI annidati (come React/Angular):

UI Component Tree
// Component interface
interface UIComponent {{ '{' }}
  render(): string;
  addClass(className: string): void;
{{ '}' }}

// Leaf: elementi base
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="${{ '{' }}this.classes.join(' '){{ '}' }}"` : '';
    return `<button${{ '{' }}classAttr{{ '}' }}>${{ '{' }}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="${{ '{' }}this.classes.join(' '){{ '}' }}"` : '';
    return `<input type="${{ '{' }}this.type{{ '}' }}" placeholder="${{ '{' }}this.placeholder{{ '}' }}"${{ '{' }}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="${{ '{' }}this.classes.join(' '){{ '}' }}"` : '';
    const titleHtml = this.title ? `<h3>${{ '{' }}this.title{{ '}' }}</h3>` : '';
    const childrenHtml = this.children.map(child => child.render()).join('\n    ');

    return `<div${{ '{' }}classAttr{{ '}' }}>
  ${{ '{' }}titleHtml{{ '}' }}
  ${{ '{' }}childrenHtml{{ '}' }}
</div>`;
  {{ '}' }}
{{ '}' }}

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

Il Bridge pattern separa un'astrazione dalla sua implementazione, così che le due possano variare indipendentemente. Risolve l'esplosione combinatoria di sottoclassi quando hai due dimensioni di variabilità.

TypeScript - Bridge Base
// Implementation: interfaccia implementazione
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 ${{ '{' }}radius{{ '}' }}`);
  {{ '}' }}

  renderSquare(side: number): void {{ '{' }}
    console.log(`🎨 Drawing vector square with side ${{ '{' }}side{{ '}' }}`);
  {{ '}' }}
{{ '}' }}

class RasterRenderer implements Renderer {{ '{' }}
  renderCircle(radius: number): void {{ '{' }}
    console.log(`🖼️ Drawing raster circle (pixels) with radius ${{ '{' }}radius{{ '}' }}`);
  {{ '}' }}

  renderSquare(side: number): void {{ '{' }}
    console.log(`🖼️ Drawing raster square (pixels) with side ${{ '{' }}side{{ '}' }}`);
  {{ '}' }}
{{ '}' }}

// Abstraction: forma astratta
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;
  {{ '}' }}
{{ '}' }}

// Utilizzo: combina astrazioni e implementazioni
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

// Senza Bridge: avresti bisogno di VectorCircle, RasterCircle, VectorSquare, RasterSquare
// Con 3 forme e 3 renderer = 9 classi!
// Con Bridge: 3 forme + 3 renderer = 6 classi

Bridge: Evitare Esplosione di Sottoclassi

Problema risolto da Bridge: due dimensioni di variabilità senza esplosione combinatoria:

❌ Senza Bridge: Esplosione Combinatoria
// ❌ Approccio con ereditarietà: esplosione di classi
class SmallRedCircle {{ '{' }}{{ '}' }}
class SmallBlueCircle {{ '{' }}{{ '}' }}
class SmallGreenCircle {{ '{' }}{{ '}' }}
class MediumRedCircle {{ '{' }}{{ '}' }}
class MediumBlueCircle {{ '{' }}{{ '}' }}
class MediumGreenCircle {{ '{' }}{{ '}' }}
class LargeRedCircle {{ '{' }}{{ '}' }}
class LargeBlueCircle {{ '{' }}{{ '}' }}
class LargeGreenCircle {{ '{' }}{{ '}' }}

// 3 size × 3 colors = 9 classi solo per Circle!
// Aggiungi Square, Triangle → 27 classi!
// Aggiungi un colore → +9 classi!
✅ Con Bridge: Dimensioni Separate
// Implementation: colori
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: forme con dimensione
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 ${{ '{' }}this.size{{ '}' }} circle with ${{ '{' }}this.color.fill(){{ '}' }} color`);
  {{ '}' }}
{{ '}' }}

class ColoredSquare extends ColoredShape {{ '{' }}
  constructor(color: Color, private size: string) {{ '{' }}
    super(color);
  {{ '}' }}

  draw(): void {{ '{' }}
    console.log(`🟦 Drawing ${{ '{' }}this.size{{ '}' }} square with ${{ '{' }}this.color.fill(){{ '}' }} color`);
  {{ '}' }}
{{ '}' }}

// Utilizzo: combina liberamente
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 forme + 3 colori = 5 classi (vs 6 con ereditarietà)
// Aggiungi 1 colore → +1 classe (vs +2)
// Scalabile linearmente!

Bridge per Cross-Platform UI

Esempio pratico: UI che funziona su diverse piattaforme:

Cross-Platform Bridge
// Implementation: piattaforme
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: [${{ '{' }}title{{ '}' }}] ${{ '{' }}message{{ '}' }}`);
  {{ '}' }}

  showNotification(message: string): void {{ '{' }}
    console.log(`🪟 Windows Notification: ${{ '{' }}message{{ '}' }}`);
  {{ '}' }}
{{ '}' }}

class MacOSPlatform implements Platform {{ '{' }}
  showDialog(title: string, message: string): void {{ '{' }}
    console.log(`🍎 macOS Alert: [${{ '{' }}title{{ '}' }}] ${{ '{' }}message{{ '}' }}`);
  {{ '}' }}

  showNotification(message: string): void {{ '{' }}
    console.log(`🍎 macOS Banner: ${{ '{' }}message{{ '}' }}`);
  {{ '}' }}
{{ '}' }}

class LinuxPlatform implements Platform {{ '{' }}
  showDialog(title: string, message: string): void {{ '{' }}
    console.log(`🐧 Linux Dialog: [${{ '{' }}title{{ '}' }}] ${{ '{' }}message{{ '}' }}`);
  {{ '}' }}

  showNotification(message: string): void {{ '{' }}
    console.log(`🐧 Linux Notify: ${{ '{' }}message{{ '}' }}`);
  {{ '}' }}
{{ '}' }}

// Abstraction: applicazione
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");
  {{ '}' }}
{{ '}' }}

// Utilizzo: stessa app su diverse piattaforme
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

Quando Usare Ogni Pattern

✅ Usa Composite quando:

  • Vuoi rappresentare gerarchie part-whole (alberi)
  • Client devono trattare oggetti singoli e composizioni uniformemente
  • Strutture ricorsive: file system, menu, UI components
  • Operazioni devono propagarsi attraverso la gerarchia

✅ Usa Bridge quando:

  • Hai due dimensioni di variabilità indipendenti
  • Vuoi evitare esplosione combinatoria di sottoclassi
  • Astrazione e implementazione devono variare indipendentemente
  • Cross-platform development, rendering engines, database drivers

Composite e Bridge Combinati

Document Editor con Entrambi
// BRIDGE: separare document da storage
interface DocumentStorage {{ '{' }}
  save(content: string): void;
  load(): string;
{{ '}' }}

class LocalFileStorage implements DocumentStorage {{ '{' }}
  save(content: string): void {{ '{' }}
    console.log(`💾 Saving to local file: ${{ '{' }}content.substring(0, 30){{ '}' }}...`);
  {{ '}' }}

  load(): string {{ '{' }}
    return "Loaded from local file";
  {{ '}' }}
{{ '}' }}

class CloudStorage implements DocumentStorage {{ '{' }}
  save(content: string): void {{ '{' }}
    console.log(`☁️ Uploading to cloud: ${{ '{' }}content.substring(0, 30){{ '}' }}...`);
  {{ '}' }}

  load(): string {{ '{' }}
    return "Loaded from cloud";
  {{ '}' }}
{{ '}' }}

// COMPOSITE: struttura documento
interface DocumentElement {{ '{' }}
  render(): string;
{{ '}' }}

class Paragraph implements DocumentElement {{ '{' }}
  constructor(private text: string) {{ '{' }}{{ '}' }}

  render(): string {{ '{' }}
    return `<p>${{ '{' }}this.text{{ '}' }}</p>`;
  {{ '}' }}
{{ '}' }}

class Heading implements DocumentElement {{ '{' }}
  constructor(
    private text: string,
    private level: number
  ) {{ '{' }}{{ '}' }}

  render(): string {{ '{' }}
    return `<h${{ '{' }}this.level{{ '}' }}>${{ '{' }}this.text{{ '}' }}</h${{ '{' }}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${{ '{' }}content{{ '}' }}\n</section>`;
  {{ '}' }}
{{ '}' }}

// Document con Bridge per 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: ${{ '{' }}content{{ '}' }}`);
  {{ '}' }}
{{ '}' }}

// Utilizzo combinato
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...

Conclusione

Composite e Bridge risolvono problemi strutturali complessi. Composite unifica oggetti singoli e composizioni per strutture ad albero ricorsive, mentre Bridge separa astrazione da implementazione per evitare esplosioni combinatorie. Usali per architetture scalabili e manutenibili.

🎯 Punti Chiave

  • Composite = gerarchie ad albero, tratta leaf e composite uniformemente
  • Usa Composite per file system, menu, UI trees
  • Bridge = separa astrazione da implementazione
  • Bridge evita N×M sottoclassi (diventa N+M classi)
  • Usa Bridge per cross-platform, multi-renderer, multi-database
  • Entrambi favoriscono composizione su ereditarietà

Domande frequenti

Qual è il principale obiettivo del Composite Pattern?

Il principale obiettivo del Composite Pattern è comporre oggetti in strutture ad albero per rappresentare gerarchie part-whole e permettere ai client di trattare singoli oggetti e composizioni di oggetti in modo uniforme.

Come risolve il Bridge Pattern l'esplosione combinatoria di sottoclassi?

Il Bridge Pattern separa un'astrazione dalla sua implementazione, così che le due possano variare indipendentemente, evitando quindi l'esplosione combinatoria di sottoclassi quando ci sono due dimensioni di variabilità.

Qual è l'esempio pratico del Composite Pattern per UI Components?

Un esempio realistico del Composite Pattern per UI Components è la rappresentazione dei componenti UI annidati, come quelli utilizzati in framework come React o Angular.

In che modo il Bridge Pattern può essere applicato a una UI che funziona su diverse piattaforme?

Il Bridge Pattern può essere utilizzato per creare una UI che funzioni su diverse piattaforme, separando l'astrazione della UI dalla sua implementazione specifica per ogni piattaforma.

Fonti e approfondimenti

Prova Questi Strumenti

Strumenti gratuiti correlati a questo argomento.

Commenti

Caricamento commenti...

Accedi per commentare

Discuti questo articolo nella community

Unisciti al gruppo Telegram per discutere con altri sviluppatori, fare domande e condividere le tue esperienze.

Ti è piaciuto questo articolo?

Esplora altri contenuti sul blog o scopri i miei progetti