Sono in procinto di creare un'applicazione che richiede una registrazione approfondita dei punti nel tempo in cui si verificano determinati eventi. Ad esempio, quando esegue il rendering di una sequenza di forme diverse sullo schermo, abbiamo bisogno di un file di log con informazioni come 'forma A resa in superficie al tempo X, forma B resa in superficie al tempo Y, superficie ruotata al tempo C' ecc. in risposta ai commenti Questi nomi (A, B) dovrebbero essere significativi e saranno definiti dall'utente (es. 'MyGroupOfRectangles') o generati automaticamente (come tipo di forma + numero, ad esempio 'Rettangolo1' o per bitmap / avis / ... usa il nome del file). La ragione principale di ciò è che la maggior parte delle volte il file di log viene interpretato semplicemente dall'utente che lo legge e controlla rapidamente se la sequenza sta facendo ciò che desidera.
Per far sì che ciò accada, è chiaro che al momento in cui viene invocata la funzione di registro, è necessario conoscere il nome della forma su cui verrà eseguito il log. Si potrebbe semplicemente dare qualsiasi tipo di oggetto che verrà registrato su un membro di una stringa. Tuttavia, se ci penso, ci sono alcune domande di implementazione e di design che mi fanno dubitare di questo approccio. Ma altri approcci a loro volta hanno altri problemi.
La domanda principale è (quasi filosofico - probabilmente sto pensando troppo a questo): un oggetto dovrebbe sapere che è il proprio nome? Dopotutto è solo un dettaglio di implementazione qui, usato esclusivamente per la registrazione - se non volessi registrare le Shapes con il loro nome, non avrebbero bisogno di essere nominati affatto.
Quindi ha senso inserire il nome anche lì, o sarebbe meglio mantenere una mappa da qualche parte che collega le istanze dell'oggetto a un nome? Qualcosa come
Map< Shape, string > shapeNames;
string NameForShape( Shape s )
{
return shapeNames.Contains( s ) ? shapeNames[ s ] : "<unnamed>";
}
Questo è molto poco invadente, ma introduce alcuni altri potenziali problemi nel mantenere la mappa aggiornata con le forme esistenti: se una forma viene distrutta, il nome deve anche essere cancellato dalla mappa.
L'altra opzione (o se ci sono molte altre opzioni, fammi sapere) è far sì che Shape restituisca il suo nome. Essendo un'interfaccia potrebbe essere così:
interface Shape
{
void Render();
...
string Name();
}
Tuttavia, questo significa che ogni implementazione deve prendersi cura di fornire l'implementazione Name()
e probabilmente lo faranno tutti allo stesso modo, come
class Rect : Shape
{
public:
Rect( string name ) : { this->name = name; }
string Name() { return name; }
private:
string name;
}
Questo è un po 'di carattere essenziale e DRY è una regola santa, quindi solleva più domande: mi libero di eliminare l'interfaccia pura e di renderla astratta (non ideale per i test delle unità)? Oppure aggiungo un livello aggiuntivo con un'implementazione Shape predefinita come NamedShape che implementa parzialmente Shape e fornisce semplicemente Name () (il livello di ereditarietà extra non è l'ideale)?