Modello Flyweight in Java

1. Panoramica

In questo articolo, daremo uno sguardo al modello di progettazione dei pesi mosca. Questo modello viene utilizzato per ridurre l'impronta di memoria. Può anche migliorare le prestazioni nelle applicazioni in cui la creazione di istanze degli oggetti è costosa.

In poche parole, il modello flyweight si basa su una fabbrica che ricicla gli oggetti creati immagazzinandoli dopo la creazione. Ogni volta che viene richiesto un oggetto, la fabbrica cerca l'oggetto per verificare se è già stato creato. In caso affermativo, viene restituito l'oggetto esistente, altrimenti ne viene creato uno nuovo, archiviato e quindi restituito.

Lo stato dell'oggetto flyweight è costituito da un componente invariante condiviso con altri oggetti simili ( intrinseco ) e da un componente variante che può essere manipolato dal codice client ( estrinseco ).

È molto importante che gli oggetti a peso mosca siano immutabili: qualsiasi operazione sullo stato deve essere eseguita dalla fabbrica.

2. Implementazione

Gli elementi principali del pattern sono:

  • un'interfaccia che definisce le operazioni che il codice client può eseguire sull'oggetto flyweight
  • una o più implementazioni concrete della nostra interfaccia
  • una factory per gestire l'istanziazione e la memorizzazione nella cache degli oggetti

Vediamo come implementare ogni componente.

2.1. Interfaccia del veicolo

Per cominciare, creeremo un'interfaccia del veicolo . Poiché questa interfaccia sarà il tipo di ritorno del metodo factory, dobbiamo assicurarci di esporre tutti i metodi rilevanti:

public void start(); public void stop(); public Color getColor();

2.2. Veicolo in cemento

Successivamente, creiamo una classe di auto come veicolo concreto . La nostra macchina implementerà tutti i metodi dell'interfaccia del veicolo. Per quanto riguarda il suo stato, avrà un motore e un campo colore:

private Engine engine; private Color color;

2.3. Fabbrica di veicoli

Ultimo ma non meno importante, creeremo la VehicleFactory . Costruire un nuovo veicolo è un'operazione molto costosa, quindi la fabbrica creerà solo un veicolo per colore.

Per fare ciò, teniamo traccia dei veicoli creati utilizzando una mappa come semplice cache:

private static Map vehiclesCache = new HashMap(); public static Vehicle createVehicle(Color color) { Vehicle newVehicle = vehiclesCache.computeIfAbsent(color, newColor -> { Engine newEngine = new Engine(); return new Car(newEngine, newColor); }); return newVehicle; }

Si noti come il codice client possa influenzare solo lo stato estrinseco dell'oggetto (il colore del nostro veicolo) passandolo come argomento al metodo createVehicle .

3. Casi d'uso

3.1. Compressione dati

L'obiettivo del pattern flyweight è ridurre l'utilizzo della memoria condividendo quanti più dati possibile, quindi è una buona base per algoritmi di compressione senza perdita di dati. In questo caso, ogni oggetto flyweight agisce come un puntatore e il suo stato estrinseco è l'informazione dipendente dal contesto.

Un classico esempio di questo utilizzo è in un word processor. Qui, ogni personaggio è un oggetto flyweight che condivide i dati necessari per il rendering. Di conseguenza, solo la posizione del carattere all'interno del documento occupa memoria aggiuntiva.

3.2. Memorizzazione nella cache dei dati

Molte applicazioni moderne utilizzano le cache per migliorare i tempi di risposta. Il modello dei pesi mosca è simile al concetto centrale di una cache e può adattarsi bene a questo scopo.

Naturalmente, ci sono alcune differenze chiave nella complessità e nell'implementazione tra questo modello e una tipica cache generica.

4. Conclusione

Per riassumere, questo rapido tutorial si è concentrato sul modello di progettazione dei pesi mosca in Java. Abbiamo anche verificato alcuni degli scenari più comuni che coinvolgono il pattern.

Tutto il codice degli esempi è disponibile nel progetto GitHub.