Non usare neanche se puoi evitarlo. Utilizzare una funzione di fabbrica che restituisce un tipo di opzione, una tupla o un tipo di somma dedicato. In altre parole, rappresentano un valore potenzialmente predefinito con un tipo diverso da un valore garantito da non default.
Innanzitutto, elenchiamo i desiderati, quindi pensiamo a come possiamo esprimerlo in alcune lingue (C ++, OCaml, Python)
- rileva l'uso indesiderato di un oggetto predefinito al momento della compilazione.
- chiarire se un determinato valore è potenzialmente predefinito o meno durante la lettura del codice.
- scegli il nostro valore predefinito ragionevole, se applicabile, una volta per tipo . Sicuramente non scegliere un valore predefinito potenzialmente diverso in ogni sito di chiamata .
- semplificare la
grep
ricerca di potenziali errori da parte di strumenti di analisi statica o di un essere umano .
- Per alcune applicazioni , il programma dovrebbe continuare normalmente se inaspettatamente viene assegnato un valore predefinito. Per altre applicazioni , il programma dovrebbe arrestarsi immediatamente se viene assegnato un valore predefinito, idealmente in modo informativo.
Penso che la tensione tra il Null Object Pattern e i puntatori null provenga da (5). Se riusciamo a rilevare gli errori abbastanza presto, però, (5) diventa discutibile.
Consideriamo questa lingua per lingua:
C ++
A mio avviso, una classe C ++ dovrebbe essere generalmente costruibile in modo predefinito poiché facilita le interazioni con le librerie e semplifica l'utilizzo della classe in contenitori. Semplifica anche l'eredità poiché non è necessario pensare a quale costruttore di superclasse chiamare.
Tuttavia, ciò significa che non si può sapere con certezza se un valore di tipo MyClass
è nello "stato predefinito" oppure no. Oltre a mettere in un bool nonempty
campo o simile per emergere default in fase di esecuzione, il meglio che puoi fare è produrre nuove istanze MyClass
in un modo che costringa l'utente a verificarlo .
Consiglierei di utilizzare una funzione di fabbrica che restituisce a std::optional<MyClass>
, std::pair<bool, MyClass>
o un riferimento di valore r a a std::unique_ptr<MyClass>
se possibile.
Se si desidera che la funzione di fabbrica restituisca un tipo di stato "segnaposto" diverso da uno predefinito MyClass
, utilizzare a std::pair
e assicurarsi di documentare che la funzione funzioni.
Se la funzione di fabbrica ha un nome univoco, è facile grep
per il nome e cercare la sciattezza. Tuttavia, è difficile grep
per i casi in cui il programmatore avrebbe dovuto usare la funzione di fabbrica ma non l'ha fatto .
OCaml
Se stai usando un linguaggio come OCaml, puoi semplicemente usare un option
tipo (nella libreria standard OCaml) o un either
tipo (non nella libreria standard, ma facile da usare). O un defaultable
tipo (sto inventando il termine defaultable
).
type 'a option =
| None
| Some of 'a
type ('a, 'b) either =
| Left of 'a
| Right of 'b
type 'a defaultable =
| Default of 'a
| Real of 'a
A defaultable
come mostrato sopra è meglio di una coppia perché l'utente deve eseguire il pattern match per estrarre il 'a
e non può semplicemente ignorare il primo elemento della coppia.
L'equivalente del defaultable
tipo come mostrato sopra può essere usato in C ++ usando a std::variant
con due istanze dello stesso tipo, ma parti std::variant
dell'API sono inutilizzabili se entrambi i tipi sono uguali. Inoltre è un uso strano std::variant
dal momento che i suoi costruttori di tipo sono senza nome.
Pitone
Non si ottiene comunque alcun controllo in fase di compilazione per Python. Ma, essendo tipizzato dinamicamente, in genere non ci sono circostanze in cui è necessaria un'istanza segnaposto di qualche tipo per placare il compilatore.
Consiglierei di lanciare un'eccezione quando si sarebbe costretti a creare un'istanza predefinita.
Se ciò non è accettabile, consiglierei di creare un DefaultedMyClass
elemento che eredita MyClass
e di restituirlo dalla funzione di fabbrica. Ciò ti offre flessibilità in termini di funzionalità di "estrazione" in casi predefiniti, se necessario.