La prima versione è identica a come sono spesso progettate le raccolte indicizzate o con chiave di ricerca: provare a recuperare un valore non esistente restituirà un valore che denota l'assenza di un valore, ad es. null
o nil
. Per un contenitore generico è indesiderabile perché significa che non è possibile distinguere tra un valore che non è presente e un valore che è null
. Tuttavia, nel tuo caso, ciò non costituirà un problema, poiché null
non è un valore possibile, hai solo Server
oggetti.
Un'altra possibilità è lanciare un'eccezione se il valore non viene trovato. Ma, cercare qualcosa in un dizionario e non trovarlo non è una situazione eccezionale, è abbastanza normale.
Nel mondo .NET esiste il pattern Try
: bool TryGetServerWithIP(IP ip, out Server server)
restituisce un valore booleano che indica se il server non è stato trovato e il valore effettivo sarà disponibile in un argomento passato per riferimento:
Server myServer;
if TryGetServerWithIP(new IP(192, 168, 0, 1), myServer) {
// you can use 'myServer' here
}
Ma in realtà, il modo migliore IMO è di restituire un tipo Option
(noto anche come Maybe
):
Option<Server> GetServerWithIP(IP ip)
Inoltre, spesso è bello avere questo:
Server GetServerWithIPOrElse(IP ip, Server default)
Se non hai familiarità con i tipi Option
o Maybe
, questo è fondamentalmente isomorfo per un contenitore che è vuoto o ha esattamente un elemento. È piuttosto carino per un tipo di Option
implementare l'API contenitore standard (ad esempio IEnumerable
in .NET o Iterable
in Java). Ciò consente, ad esempio, di utilizzare il linguaggio incorporato foreach
loop per elaborare il valore solo se esiste. Inoltre, Maybe
può essere una monade, che è di nuovo piuttosto carina solo per le proprietà monadiche, ma ancora di più per le lingue che hanno il supporto integrato per le monade, come C #.