Prima di iniziare devo dire che questo esempio probabilmente non esisterà mai in quella forma nell'app reale (almeno non dovrebbe).
Ecco perché (IMHO):
1) Dirigi direttamente l'implementazione dal codice cliente:
Prima di tutto si passa una stringa per rendere il metodoEnemyShip - è pratica prettamente errata passare le informazioni sul tipo come una stringa MA la cosa triste di quell'esempio è che il tuo input è una sorta di indicatore diretto per l'implementazione.
Intendo dire che il tuo shipType sta puntando all'implementazione di EnemyShip di un rapporto uno a uno tra le stringhe di input e le classi di spedizione.
Se ottieni argomenti di input dal "mondo esterno" (DB, API, interfaccia utente, ecc.), potrebbe essere ragionevole fornire una sorta di mappatura o una semplice fabbrica (come questa dal tuo esempio) che seleziona il metodo di produzione corretto (o basta istanziare una classe specifica in base a "input esterno".
class PaymentProvider {
private creators: { [key: string]: PaymentFactoryMethod };
// ...
public getPayment(paymentSignature: string): Payment | undefined {
const createPayment = this.creators[paymentSignature];
return createPayment ? createPayment() : undefined;
}
}
MA se vuoi fornire questo stabilimento per uso generale,
Suppongo che potresti finire per passarlo a uno dei tuoi corsi. Quindi potresti voler fare qualcosa del tipo:
EnemyShip enemy = factory.makeEnemyShip("U")
// or what's worse:
this.enemy = this.factory.makeEnemyShip("U")
Per me questo codice viola una delle regole più importanti del pattern factory:
Lascia che il codice client non sia a conoscenza dell'implementazione fornita dalla fabbrica.
Tuttavia definire la fabbrica in questo modo ha ancora dei vantaggi, penso che il principale sia l'incapsulamento della logica che sta dietro la creazione della nave nemica (potrebbe essere complessa).
A mio parere, in generale, è meglio passare fabbrica come dipendenza e utilizzare il metodo Factory Method o Abstract Factory, e ciò che è più importante quando si tratta di fabbriche considerare se ne hai davvero bisogno.
2) Il tuo codice viola il principio di apertura / chiusura
Come hai notato, questo codice ha predefinito tutte le possibili implementazioni di EnemyShip - che è spesso (anche molto spesso - ma non sempre) una cattiva idea.
Perché:
- è difficile aggiungere un nuovo tipo - devi refactoring questo codice
- non è dinamico
Correzione per questo problema di istruzione "if" codificato è Map o Dictionary. Al momento non è possibile aggiungere nuove implementazioni durante il runtime - Se si disponesse di un dizionario (o di una mappa) che associa tipi o predicati a particolari classi, si registrerebbe facilmente e si annullerebbero la registrazione di nuove fabbriche.
TUTTAVIA Avresti comunque bisogno di un posto per configurare questo stabilimento.
Per riassumere
Penso che l'esempio che hai fornito sia una sorta di materiale didattico che impara a sbarazzarsi della parola chiave new
piuttosto che fornisce un vero e proprio modello di app utile.