Come posso evitare l'uso di stringhe?

1

Sto implementando un programma in cui l'utente può 'creare una scala musicale' da una varietà di note (identificate dai loro nomi), e il programma genererà musica da questa scala.

Voglio implementare una classe che prende una nota e una lunghezza e genera un SoundWave . Quindi un'opzione sarebbe quella di esporre il seguente metodo:

public SoundWave GenerateNote(string noteName, double length);

Tuttavia, penso che sarebbe meglio cercare di evitare string s. Quindi posso pensare a due opzioni aggiuntive:

public SoundWave GenerateNote(Note note, double length);
// Note is a simple object with a string name and a double frequency.

E

public void Scale { get; set; }
public SoundWave GenerateNote(int noteIndex, double length);

Il fatto è che non potrò evitare string s completamente, perché come ho detto l'utente selezionerà le note identificate dai loro nomi. Quindi quale sarebbe l'opzione migliore che ti viene in mente?

    
posta Aviv Cohn 20.06.2015 - 12:58
fonte

4 risposte

10

Il punto di evitare stringhe non è che siano intrinsecamente cattive e non dovrebbero mai essere usate. Se così fosse, li omettere dai nostri linguaggi di programmazione.

Ciò che dovrebbe essere evitato è l'uso di stringhe per rappresentare valori alternativi quando i valori possibili sono in realtà un piccolo insieme di opzioni predefinite, piuttosto che qualsiasi stringa possibile. Il pericolo che qualcuno dimentichi quali valori sono consentiti e quali no è troppo grande.

Pertanto, sono stati inventati meccanismi per supportare meglio questo caso comune. Nella logica aziendale, dovresti utilizzare enum s anziché stringhe; nelle GUI, è necessario disporre di elenchi a discesa anziché di campi di immissione di testo per tali dati. Ma nulla ti impedisce di usare stringhe per dati che sono davvero arbitrari, come i nomi degli utenti.

    
risposta data 20.06.2015 - 13:17
fonte
3

Thing is, I won't be able to avoid strings completely, because as I said the user will select notes identified by their names. So what would be the best option you can think of?

Questo sarà un programma a riga di comando? Se è così, è ovviamente impossibile evitare di occuparsi di string poiché è ciò che l'utente sta digitando. Darei alla classe Note un metodo statico parse(string s) che produce un'istanza Note .

Una volta che hai una GUI, probabilmente avrai l'utente a scegliere tra una selezione di note esistenti.

    
risposta data 20.06.2015 - 13:14
fonte
1

Assumendo ci sono un insieme finito di note, ad es. A, C, D, E, ..., sembra che un tipo enumerato si adatti meglio al tuo scopo. Un tipo enumerato (disponibile nella maggior parte dei linguaggi di programmazione) può assumere valori da un piccolo insieme, in cui la definizione del tipo contiene tutti i valori consentiti. Ad esempio, potresti utilizzare valori MON , TUE , WED , THU , FRI , SAT , SUN per un tipo enum di DayOfWeek o A , C , D , ... per Note type.

L'uso delle enumerazioni dà al tuo codice una maggiore leggibilità e rende impossibile alcuni tipi di errori, come passare la stringa xyz come nome della nota. Con un tipo enumerato non è semplicemente possibile passare un valore illegale.

    
risposta data 20.06.2015 - 15:13
fonte
1

Non confondere i problemi di interfaccia utente con i problemi di interfaccia di programmazione .

Il fatto che l'utente inserisca le note per nome è un problema di interfaccia utente e non riguarda assolutamente la tua funzione GenerateNote() , che è parte di un'interfaccia di programmazione.

Di fatto, l'interfaccia utente potrebbe, in teoria, consentire all'utente di selezionare tra diverse notazioni, (A, B, C ...) o (Do, Re, Mi ...) così chiaramente, il compito di mappare le stringhe inserite dall'utente in oggetti note reali dovrebbe essere gestito dall'interfaccia utente e queste stringhe non dovrebbero mai essere propagate ad altre parti della tua applicazione. Il fatto che un oggetto Note possa contenere il proprio nome non è nemmeno necessariamente pertinente alla mappatura, poiché l'utente può inserire "Do" e l'interfaccia utente dovrà mapparla su un oggetto Note con il nome " UN". Allo stesso modo, quando l'interfaccia utente visualizza gli oggetti Note all'utente, è necessario eseguire la trasformazione inversa e, di nuovo, potrebbe essere necessario mostrare "Do" mentre l'oggetto porta il nome "A". Quindi, i due sono completamente indipendenti.

Un noteIndex di tipo int è cattivo come una stringa, perché stai utilizzando un tipo di dati generici là dove potrebbe essere usato un tipo di dati più specifico (una classe Note effettiva). Il tipo di dati generici non ha senso in sé e per sé, e il suo significato è in effetti qualunque sia il significato assegnato ad esso in fase di esecuzione (anziché in fase di compilazione) dal codice che lo gestisce, quindi la sua esistenza costituisce un completamente inutile e pericoloso (vedere soggetto a errore) indirection . La migliore pratica nell'ingegneria del software consiste nell'utilizzare un tipo speciale per ogni diverso concetto con cui la logica si occupa. Ecco cos'è "Strong Typing".

Quindi, sicuramente vai con un oggetto Note .

Perché non usare solo una frequenza double e farla finita con? Bene, ancora una volta, la risposta è "Strong Typing". Prendiamo un esempio da un'altra applicazione: supponiamo che tu stia scrivendo un software che si occupa di automobili, quindi hai a che fare con cose come "velocità" e "consumo di carburante". La cosa corretta da fare è avere un tipo di dati "Velocità", che contenga un doppio e un tipo di dati "FuelConsumption", che contenga un altro doppio, in modo da non passare mai il doppio, perché a un certo punto un doppio che era destinato per "Speed", erroneamente, si passerebbe per errore a una funzione che prevedeva un doppio che avrebbe dovuto significare "FuelConsumption", e allora accadranno tutti i tipi di cose divertenti. Buona fortuna con il debug di un sistema costruito in questo modo! Con una strong digitazione, il compilatore si assicura che non si possa fare la cosa sbagliata.

    
risposta data 20.06.2015 - 15:18
fonte