Promemoria: se hai dei suggerimenti, ricordati di mettere il motivo in modo obiettivo, ad esempio "avere due funzioni SetInt()
distinte nello stesso file viola le aspettative del lettore che saranno sovraccariche e ostacola la capacità di trova la funzione giusta con ctrl + F. "
Problema:
Occasionalmente sono necessarie API di basso livello / pericolose. Dovrebbero essere nascosti, ma non possono essere privati. Ad esempio, le funzioni per manipolare i dati di salvataggio aggiuntivi (non caricati), rinominare / eliminare i file di configurazione dei dati di salvataggio sottostanti su disco o impedire che eventuali salvataggi futuri vengano scritti su disco. Come faccio a mantenere l'API pulita, quindi le classi normali non vedono questi metodi ausiliari?
In C ++, queste funzioni ausiliarie sarebbero private e le classi che necessitavano dell'accesso sarebbero classi di amici. In C #, il mio primo pensiero è stato quello di usare questo:
Pattern Pseudo-Facciata, nascondendo i metodi ausiliari:
// The Save.Foo() functions are used all the time. Concise/simple API needed.
public static class Save
{
public static void SetInt(string key, int value)
{
Save_Implementation.SetInt(currentSaveData, key, value);
}
}
public static class Save_Implementation // ancillary or dangerous APIs
{
public static void SetInt(object data, string key, int value) { /* ... */ }
public static void StopAllSaves() { /* ... */ }
public static string GetCurrentFilename() { /* ... */ }
}
Funziona, ma dovrei correlare le classi per chiarire meglio che fanno parte della stessa cosa. Sottoclasse? Non posso, è statico. Spazio dei nomi? Non possiamo, dobbiamo digitare questi nomi di funzioni con una frequenza brutale. Classe annidata? Sì, per favore.
Classe nidificata:
public static class Save
{
public static void SetInt(string key, int value)
{
Impl.SetInt(currentSaveData key, value);
}
public static class Impl // ancillary or dangerous APIs
{
public static void SetInt(object data, string key, int value) { /* ... */ }
public static void StopAllSaves() { /* ... */ }
public static string GetCurrentFilename() { /* ... */ }
}
}
È meglio, ma più cauto di quanto preferire, dal momento che ci sono metodi duplicati nello stesso file. (I.e, SetInt()
chiama Impl.SetInt(currentSaveData)
.) Successivamente ho provato a dividerlo:
Classi parziali, con elementi ausiliari in un file diverso:
Save.cs:
public static partial class Save
{
public static void SetInt(string key, int value)
{
Impl.SetInt(currentSaveData, key, value);
}
public static partial class Impl // ancillary or dangerous APIs
{
}
}
SaveImplementation.cs:
public static partial class Save
{
public static partial class Impl // ancillary or dangerous APIs
{
public static void SetInt(object data, string key, int value) { /* ... */ }
public static void StopAllSaves() { /* ... */ }
public static string GetCurrentFilename() { /* ... */ }
}
}
Funziona, ma l'IDE non è abbastanza intelligente da aprire il file giusto quando passo alla definizione di Salva o Salva.Impl. C'è un modo perfetto per organizzare questo, o sarà sempre un compromesso?
Modifica: Save
è una sostituzione drop-in per la funzionalità di salvataggio predefinita del motore di gioco, quindi è ideale per clonare l'API esistente (ed essere statica).