Menu
Coddy logo textTech

Singleton

Fa parte della sezione Programmazione orientata agli oggetti del percorso Dart di Coddy. Lezione 90 di 110.

Il pattern Singleton garantisce che una classe abbia una sola istanza in tutta l'applicazione e fornisce un punto di accesso globale a essa. È utile quando serve esattamente un oggetto per coordinare le operazioni in tutto il sistema, come un gestore della configurazione, una connessione al database o un servizio di logging.

In Dart, puoi implementare un Singleton usando un costruttore factory combinato con un'istanza statica privata:

class AppConfig {
  static final AppConfig _instance = AppConfig._internal();
  
  String appName = 'MyApp';
  String version = '1.0.0';
  
  // Costruttore con nome privato
  AppConfig._internal();
  
  // Il costruttore factory restituisce la stessa istanza
  factory AppConfig() {
    return _instance;
  }
}

void main() {
  var config1 = AppConfig();
  var config2 = AppConfig();
  
  config1.appName = 'UpdatedApp';
  
  print(config2.appName);  // UpdatedApp
  print(identical(config1, config2));  // true
}

Il costruttore privato _internal() impedisce l’istanziazione esterna. Il campo statico _instance contiene l’unica istanza, creata una sola volta quando viene caricata la classe. Ogni chiamata a AppConfig() restituisce questa stessa istanza, quindi le modifiche apportate tramite un riferimento sono visibili ovunque.

Usa i Singleton con moderazione: introducono uno stato globale, che può rendere più difficile il testing. Sono più indicati per risorse realmente condivise che necessitano di uno stato coerente in tutta l'applicazione.

challenge icon

Sfida

Facile

Costruiamo un gestore delle impostazioni di un gioco usando il pattern Singleton! Creerai un sistema che garantisce l'esistenza di una sola istanza delle impostazioni del gioco in tutta l'applicazione, così tutte le parti del gioco condividono la stessa configurazione.

Organizzerai il codice in due file:

  • game_settings.dart: crea una classe GameSettings che implementa il pattern Singleton. Il gestore delle impostazioni dovrà avere:
    • Un'istanza privata, statica e final che contiene l'unico oggetto GameSettings
    • Un costruttore denominato privato per impedire l'istanziazione esterna
    • Un costruttore factory che restituisce sempre la stessa istanza
    • Tre campi per le impostazioni: difficulty (String, valore predefinito: "Normal"), soundEnabled (bool, valore predefinito: true) e playerName (String, valore predefinito: "Player1")
    • Un metodo displaySettings() che stampa le impostazioni correnti in questo formato: Settings: [playerName] | Difficulty: [difficulty] | Sound: [on/off] (stampa "on" se soundEnabled è true, "off" se è false)
  • main.dart: importa le impostazioni del gioco e dimostra che il Singleton funziona correttamente:
    • Ottieni l'istanza delle impostazioni e chiamala settings1
    • Chiama displaySettings() per mostrare i valori predefiniti
    • Modifica le impostazioni: cambia playerName in "Hero", difficulty in "Hard" e soundEnabled in false
    • Ottieni un altro riferimento alle impostazioni e chiamalo settings2
    • Chiama displaySettings() su settings2 per dimostrare che riflette le modifiche apportate tramite settings1
    • Stampa se settings1 e settings2 sono identici usando: Same instance: [true/false]

Questo dimostra il vantaggio principale dei Singleton: le modifiche apportate in qualsiasi punto dell'applicazione sono immediatamente visibili in ogni altra parte, perché esiste una sola istanza!

Output previsto:

Settings: Player1 | Difficulty: Normal | Sound: on
Settings: Hero | Difficulty: Hard | Sound: off
Same instance: true

Provalo tu

import 'game_settings.dart';

void main() {
  // TODO: Ottieni l'istanza delle impostazioni e chiamala settings1
  
  // TODO: Chiama displaySettings() per mostrare i valori predefiniti
  
  // TODO: Modifica le impostazioni:
  // - Cambia playerName in "Hero"
  // - Cambia difficulty in "Hard"
  // - Cambia soundEnabled in false
  
  // TODO: Ottieni un altro riferimento alle impostazioni e chiamalo settings2
  
  // TODO: Chiama displaySettings() su settings2 per dimostrare che riflette le modifiche
  
  // TODO: Stampa se settings1 e settings2 sono identici
  // Formato: Same instance: [true/false]
}
quiz iconMettiti alla prova

Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.

Tutte le lezioni di Programmazione orientata agli oggetti

Esercitati da solo: Compilatore Dart online