Si definisce Factory un metodo che ha come unico scopo quello di creare una nuova istanza di una classe e restituire tale istanza
al chiamante (dato che si parla di "restituire", i metodi Factory saranno sempre funzioni).
Ora, ci si potrebbe chiedere perchè usare metodi factory al posto di normali costruttori. La differenza tra questi
non è da sottovalutare: i costruttori servono ad istanziare un oggetto, ma, una volta avviati, non possono "fermarsi". Con questo
voglio dire che, qualora venissero riscontrati degli errori nei parametri di creazione dell'istanza (nel caso ce ne siano), il costruttore
creerebbe comunque un nuovo oggetto, ma molto probabilmente quest'ultimo conterrebbe dati erronei. Un metodo Factory, invece, controlla
che tutto sia a posto
prima di creare il nuovo oggetto: in questo modo, se c'è qualcosa che non va, lo può comunicare
al programmatore (o all'utente), ad esempio lanciando un'eccezione o visualizzando un messaggio di errore. E' convenzione - ma è
anche logica - che un metodo Factory sia definito sempre all'interno della stessa classe che corrisponde al suo tipo di output e che
sia Shared (altrimenti non si potrebbe richiamare prima della creazione dell'oggetto, ovviamente).
Un esempio di quanto detto:
Module Module1
Class Document
'Campo statico che contiene tutti i documenti
'aperi fin'ora
Private Shared Documents As New Hashtable
'Identificatore del documento: un paragrafo nel prossimo
'capitolo spiegherà in dettaglio i significato e
'l'utilità delle variabili ReadOnly
Private ReadOnly _ID As Int16
'Nome del file e testo contenuto in esso
Private ReadOnly _FileName, _Text As String
Public ReadOnly Property ID() As Int16
Get
Return _ID
End Get
End Property
Public ReadOnly Property FileName() As String
Get
Return _FileName
End Get
End Property
Public ReadOnly Property Text() As String
Get
Return _Text
End Get
End Property
'Da notare il costruttore Private: nessun client al di
'fuori della classe può inizializzare il nuovo
'oggetto. Solo il metodo factory lo può fare
Private Sub New(ByVal ID As Int16, ByVal Path As String)
Me._ID = ID
Me._FileName = Path
Me._Text = IO.File.ReadAllText(Path)
'Me fa riferimento alla classe stessa
Documents.Add(ID, Me)
End Sub
'Il metodo factory crea un documento se non esiste l'ID
'e se il percorso su disco è diverso, altrimenti
'restituisce il documento che esiste già
Public Shared Function Create(ByVal ID As Int16, _
ByVal Path As String) As Document
If Documents.ContainsKey(ID) Then
'Ottiene il documento già esistente con questo ID
Dim D As Document = Documents(ID)
'Se coincidono sia l'ID che il nome del file,
'allora restituisce l'oggetto già esistente
If D.FileName = Path Then
Return D
Else
'Altrimenti restituisce Nothing, dato che non
'possono esistere due documenti con uguale ID,
'o si farebbe confusione
Return Nothing
End If
End If
'Se non esiste un documento con questo ID, lo crea
Return New Document(ID, Path)
End Function
End Class
Sub Main()
Dim D As Document = Document.Create(0, "C: esto.txt")
Dim E As Document = Document.Create(0, "C: esto.txt")
Dim F As Document = Document.Create(0, "C:file.txt")
Dim G As Document = Document.Create(1, "C:file.txt")
'Dimostra che se ID e Path coincidono, i due oggetti
'sono la stessa istanza
Console.WriteLine(E Is D)
'Dimostra che se l'ID esiste già, ma il Path differisce,
'l'oggetto restituito è Nothing
Console.WriteLine(F Is Nothing)
Console.ReadKey()
End Sub
End Module
Il codice sopra riportato crea volutamente tutte le situazioni contemplate all'interno del metodo factory
statico: E ha gli stessi parametri di D, quindi nel metodo factory usato per creare E viene restituita
l'istanza D già esistente; F ha lo stesso ID, quindi è Nothing. A prova di ciò, sullo schermo apparirà
il seguente output:
True
True
Classi factory e oggetti immutabili
Una classe contenente solo metodi factory è detta classe factory. Il più delle volte, l'uso di una tattica
simile a quella sopra riportata potrebbe portare alcuni dubbi: dato che esistono due variabili che puntano
alla stessa istanza, il modificarne l'una potrebbe causare l'automatica modifica dell'altra. Tuttavia, spesse
volte, gli oggetti che possono essere creati con metodi factory non espongono alcun altro metodo per la modifica
o l'eliminazione dello stesso oggetto, che quindi non può essere cambiato in alcun modo. Oggetti di questo tipo
sono detti
immutabili: un esempio di oggetti immutabili sono la stringhe. Al contrario di come si
potrebe pensare, una volta create il loro valore non può essere cambiato: l'unica cosa che si può fare
è assegnare alla variabile stringa un nuovo valore:
'Questa stringa è immutabile
Dim S As String = "Ciao"
'Viene creata una nuova stringa temporanea con valore "Buongiorno"
'e assegnata a S. "Ciao" verrà distrutta dal Garbage Colletcion
S = "Buongiorno"