CREATIONAL

Prototype

Specificare i tipi di oggetti da creare usando un'istanza prototipale e creare nuovi oggetti copiando questo prototipo.

Il Problema

Creare nuovi oggetti identici o simili a oggetti esistenti può essere costoso. Inoltre, il codice non dovrebbe dipendere dalle classi concrete degli oggetti da copiare.

La Soluzione

Delegare il processo di clonazione agli oggetti stessi. Dichiarare un'interfaccia comune per tutti gli oggetti che supportano la clonazione.

Struttura

Prototype interface con metodo clone(), ConcretePrototype che implementa clone(), e client che clona invece di creare nuove istanze.

Partecipanti:
Prototype - dichiara l'interfaccia per clonare se stesso
ConcretePrototype - implementa l'operazione di clonazione
Client - crea nuovi oggetti chiedendo a un prototipo di clonarsi
Esempi di Codice

Prototype per Clonazione Oggetti

Sistema di clonazione per configurazioni di gioco.

TYPESCRIPT
interface Prototype {
  clone(): Prototype;
}

class GameCharacter implements Prototype {
  constructor(
    public name: string,
    public health: number,
    public armor: number,
    public weapons: string[],
    public skills: Map<string, number>
  ) {}

  clone(): GameCharacter {
    // Deep clone degli array e Map
    const clonedWeapons = [...this.weapons];
    const clonedSkills = new Map(this.skills);
    
    return new GameCharacter(
      this.name,
      this.health,
      this.armor,
      clonedWeapons,
      clonedSkills
    );
  }

  display(): string {
    return `${this.name}: HP=${this.health}, Armor=${this.armor}`;
  }
}

// Prototipi predefiniti
const warriorPrototype = new GameCharacter(
  'Warrior',
  100,
  50,
  ['Sword', 'Shield'],
  new Map([['Strength', 10], ['Defense', 8]])
);

const magePrototype = new GameCharacter(
  'Mage',
  70,
  20,
  ['Staff', 'Spellbook'],
  new Map([['Intelligence', 10], ['Mana', 100]])
);

// Creazione di nuovi personaggi clonando i prototipi
const player1 = warriorPrototype.clone();
player1.name = 'Aragorn';

const player2 = magePrototype.clone();
player2.name = 'Gandalf';
player2.skills.set('Wisdom', 15);

console.log(player1.display());
console.log(player2.display());

// I prototipi originali non sono stati modificati
console.log(warriorPrototype.display());
console.log(magePrototype.display());

Prototype con Object.create (JavaScript)

Approccio nativo JavaScript per prototypal inheritance.

JAVASCRIPT
// Prototipo base
const carPrototype = {
  wheels: 4,
  engine: 'V6',
  
  start() {
    console.log(`Starting ${this.brand} with ${this.engine} engine`);
  },
  
  clone() {
    return Object.create(this);
  }
};

// Creazione di nuove auto dal prototipo
const car1 = Object.create(carPrototype);
car1.brand = 'Toyota';
car1.model = 'Camry';

const car2 = Object.create(carPrototype);
car2.brand = 'Honda';
car2.model = 'Accord';
car2.engine = 'V8'; // Override

car1.start(); // Starting Toyota with V6 engine
car2.start(); // Starting Honda with V8 engine

// Modifica del prototipo si riflette su tutti gli oggetti
carPrototype.wheels = 6;
console.log(car1.wheels); // 6
console.log(car2.wheels); // 6
Esempi nel Mondo Reale
JavaScript Object.create() - creazione di oggetti da prototipi
Game Development - clonazione di nemici, armi, power-up con statistiche simili
Editor grafici - duplicazione di forme, simboli, template
Configuration Management - clonazione di configurazioni base per ambienti diversi
Document Templates - clonazione di template email, report, contratti
Quando Usarlo
Quando il costo di creazione di un nuovo oggetto è maggiore della clonazione
Quando vuoi evitare gerarchie di factory
Quando le istanze di una classe possono avere solo poche combinazioni di stato
Quando vuoi nascondere la complessità della creazione al client
Quando NON Usarlo
Quando la clonazione è complessa (oggetti con riferimenti circolari)
Quando gli oggetti non hanno molte proprietà da copiare
Quando deep cloning è costoso o difficile da implementare