3.1 Singolo

Singleton è un modello di progettazione generico che garantisce che un'applicazione a thread singolo disponga di una singola istanza di una classe e fornisce un punto di accesso globale a questa istanza.

Singleton

Molto spesso, ai programmatori alle prime armi piace assemblare metodi di utilità in una classe statica, una classe che contiene solo metodi statici. Questo approccio presenta una serie di svantaggi: ad esempio, non è possibile passare un riferimento a un oggetto di tale classe, tali metodi sono difficili da testare e simili.

In alternativa, è stata proposta una soluzione di classe singleton: una classe che può avere un solo oggetto. Quando si tenta di creare questo oggetto, viene creato solo se non esiste già, altrimenti viene restituito un riferimento a un'istanza già esistente.

È essenziale che sia possibile utilizzare un'istanza della classe, poiché in molti casi diventa disponibile una funzionalità più ampia. Ad esempio, questa classe può implementare alcune interfacce e il suo oggetto può essere passato ad altri metodi come implementazione dell'interfaccia. Cosa non si può fare con un insieme di metodi statici.

Professionisti:

  • I metodi sono associati a un oggetto, non a una classe statica: puoi passare un oggetto per riferimento.
  • I metodi degli oggetti sono molto più facili da testare e deridere.
  • Un oggetto viene creato solo quando necessario: inizializzazione pigra dell'oggetto.
  • Accelerare il lancio iniziale del programma se ci sono molti singoli che non sono necessari per il lancio.
  • Da solo può essere ulteriormente trasformato in una strategia modello o in molti di questi oggetti.

Svantaggi:

  • Diventa più difficile controllare corse e ritardi tra thread.
  • È difficile scrivere un "solitario" multi-thread "dalla testa": l'accesso a un singleton di vecchia data, idealmente, non dovrebbe aprire un mutex. Soluzioni comprovate migliori.
  • Un conflitto tra due thread su un singolo thread incompiuto comporterà un ritardo.
  • Se l'oggetto viene creato per molto tempo, il ritardo può interferire con l'utente o interrompere il tempo reale. In questo caso, è meglio trasferire la sua creazione nella fase di inizializzazione del programma.
  • Sono necessarie funzionalità speciali per i test unitari, ad esempio per mettere la libreria in modalità "non solitaria" e isolare completamente i test l'uno dall'altro.
  • È necessaria una tattica speciale per testare il programma finito, perché anche il concetto di "lanciabilità più semplice" scompare, perché la lanciabilità dipende dalla configurazione.

3.2 Fabbrica [Metodo]

Un metodo factory è un modello di progettazione generico che fornisce sottoclassi (classi eredi) con un'interfaccia per la creazione di istanze di una determinata classe. Al momento della creazione, i discendenti possono determinare quale classe creare.

In altre parole, questo modello delega la creazione di oggetti ai discendenti della classe genitore. Ciò consente di utilizzare classi non concrete nel codice del programma, ma di manipolare oggetti astratti a un livello superiore.

Metodo di fabbrica

Questo modello definisce un'interfaccia per la creazione di un oggetto, ma lascia alle sottoclassi la decisione su quale classe basare l'oggetto. Un metodo factory consente a una classe di delegare la creazione di sottoclassi. Usato quando:

  • la classe non sa in anticipo quali oggetti di quali sottoclassi deve creare.
  • una classe è progettata in modo che gli oggetti che crea siano specificati da sottoclassi.
  • la classe delega le proprie responsabilità a una delle numerose sottoclassi helper e si prevede di determinare quale classe si assume queste responsabilità.

3.3 Fabbrica astratta

Una factory astratta è un modello di progettazione generico che fornisce un'interfaccia per la creazione di famiglie di oggetti correlati o interdipendenti senza specificarne le classi concrete.

Il modello viene implementato creando una classe astratta Factory, che è un'interfaccia per la creazione di componenti di sistema (ad esempio, per un'interfaccia a finestra, può creare finestre e pulsanti). Quindi vengono scritte le classi che implementano questa interfaccia.

Fabbrica astratta

Viene utilizzato nei casi in cui il programma deve essere indipendente dal processo e dai tipi di nuovi oggetti creati. Quando è necessario creare famiglie o gruppi di oggetti correlati, escludendo la possibilità di utilizzo simultaneo di oggetti provenienti da insiemi diversi di questi nello stesso contesto.

Punti di forza:

  • isola classi specifiche;
  • semplifica la sostituzione delle famiglie di prodotti;
  • garantisce la compatibilità del prodotto.

Diciamo che il tuo programma funziona con il file system. Quindi per lavorare in Linux hai bisogno di oggetti LinuxFile, LinuxDirectory, LinuxFileSystem. E per lavorare in Windwos, hai bisogno delle classi WindowsFile, WindowsDirectory, WindowsFileSystem.

La classe Path, creata tramite Path.of(), è proprio un caso del genere. Path non è realmente una classe, ma un'interfaccia e ha implementazioni WindowsPath e LinuxPath. E quale tipo di oggetto verrà creato è nascosto dal tuo codice e sarà deciso in fase di esecuzione.

3.4 Prototipo

Il prototipo è un modello di progettazione generativo.

Questo modello definisce i tipi di oggetti che vengono creati utilizzando un'istanza prototipo e crea nuovi oggetti copiando questo prototipo. Ti consente di allontanarti dall'implementazione e seguire il principio della "programmazione tramite interfacce".

Un'interfaccia/classe astratta nella parte superiore della gerarchia è specificata come tipo restituito e le classi discendenti possono sostituire un erede che implementa questo tipo lì. In poche parole, questo è il modello di creazione di un oggetto clonando un altro oggetto invece di crearlo tramite un costruttore.

Prototipo

Il modello è utilizzato per:

  • evitando lo sforzo aggiuntivo di creare un oggetto in modo standard (ovvero utilizzando un costruttore, poiché in questo caso verranno chiamati anche i costruttori dell'intera gerarchia antenata dell'oggetto), quando questo è proibitivo per l'applicazione.
  • evitare di ereditare il creatore dell'oggetto nell'applicazione client, come fa il pattern factory astratto.

Usa questo modello di progettazione quando al tuo programma non interessa come crea, compone e presenta i prodotti:

  • le classi istanziate sono determinate in fase di esecuzione, ad esempio, utilizzando il caricamento dinamico;
  • si vuole evitare di costruire gerarchie di classi o di fabbrica parallele alle gerarchie di classi di prodotto;
  • le istanze di classe possono trovarsi in uno dei diversi stati. Potrebbe essere più conveniente impostare il numero appropriato di prototipi e clonarli, piuttosto che istanziare manualmente la classe ogni volta nello stato appropriato.