Memorizza il nome di un oggetto nell'oggetto o esternamente?

0

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)?

    
posta stijn 06.11.2014 - 10:56
fonte

3 risposte

2

Quello che ti piacerebbe avere è un mixin o un tratto, ma non puoi averlo visto che il tuo linguaggio preferito non lo supporta. Quindi stai cercando dei modi per emularlo.

Personalmente sono d'accordo che derivare il nome di un oggetto non dovrebbe essere una sua responsabilità. Per uno, perché se la tua convenzione di denominazione cambia, devi cambiare la tua implementazione di Rect.Name . Quindi ora Rect classifica un motivo in più per cambiare, che viola SRP.

L'implementazione personalizzata di Object.toString - richiamata da @gnat nei commenti - può essere tremendamente utile per il debug, ma - forse è solo un mio pregiudizio - non metterei nulla di veramente importante, qualsiasi dato che valga la pena di essere persistito, in toString .

Trasferire la responsabilità di nominare gli oggetti in modo chiaro in una classe a parte sembra una buona idea.

Tuttavia, deve davvero tenere traccia di ogni forma esistente? Questo è ciò che ti preoccupa, e non sono sicuro del perché questo sarebbe un requisito.

Questa classe non potrebbe derivare semplicemente nomi ragionevoli per ogni dato Shape al volo? Potrei mancare qualche contesto qui. Sai sempre che tipo è una particolare istanza di Shape . Dove sono gli identificatori A , B , C provenienti da?

    
risposta data 06.11.2014 - 11:15
fonte
2

quindi, per riassumere:

  1. le tue forme hanno nomi reali, determinati da qualche entità esterna (possibilmente input dell'utente), e non sempre sono solo Circle1 ecc.
  2. non pensi che la forma debba essere responsabile di questa proprietà (nomination? nominativity?)

Bene, supponendo che non si usi un logger globale e lo stesso logger disponga di un'interfaccia sana, è possibile creare un proxy logger denominato: o passato al costruttore di Shape, oppure li si avvolge entrambi in un NamedShape che passa il proxy per ogni metodo inoltrato.

Quindi, ogni riga registrata sul proxy viene semplicemente inoltrata al registratore reale, con il nome inserito.

    
risposta data 06.11.2014 - 12:37
fonte
0

Perché non usi semplicemente RTTI per ottenere direttamente una rappresentazione di stringa del nome della classe? Sì, è definito dall'implementazione, quindi non si può dipendere dal fatto che sia una cosa esatta se si stanno passando i compilatori. Tuttavia, se hai bisogno di una registrazione leggibile dall'uomo, questa è una soluzione eccellente che non comporta l'aggiunta di una linea di codice al di fuori della classe Logger stessa.

link

    
risposta data 07.11.2014 - 05:49
fonte

Leggi altre domande sui tag