Do not confuse user interface issues with programming interface issues.
The fact that the user will enter notes by name is a user interface issue, and of absolutely no concern to your
GenerateNote() function, which is part of a programming interface.
As a matter of fact, the user interface could, in theory, allow the user to select among different notations, (A, B, C...) or (Do, Re, Mi...) so clearly, the task of mapping strings entered by the user to actual note objects should be handled by the user interface, and these strings should never be allowed to propagate to other parts of your application. The fact that a
Note object may contain its own name is not even necessarily pertinent to the mapping, since the user may enter "Do", and the user interface will have to map this to a
Note object bearing the name "A". Similarly, when the user interface displays the
Note objects back to the user, it needs to perform the reverse transformation, and again, it may need to show 'Do' while the object bears the name 'A'. So, the two are completely unrelated.
noteIndex of type
int is as bad as a string, because you are using a general purpose data type there where a more specific data type (an actual
Note class) could be used instead. The general purpose data type is meaningless in and of itself, and its meaning is in fact whatever meaning is assigned to it at runtime (instead of compile-time) by code that handles it, so its existence constitutes a completely unnecessary and dangerous (see error prone) indirection. The best practice in Software Engineering is to use a special type for each different concept that your logic deals with. That's what "Strong Typing" is all about.
So, definitely go with a
Why not just use a
double frequency and get it over with? Well, again, the answer is "Strong Typing". Take an example from a different application: suppose you are writing software that deals with automobiles, so you are dealing with things like "speed" and "fuel consumption". The proper thing to do is to have a "Speed" data type, which contains a double, and a "FuelConsumption" data type, which contains another double, so that you never pass doubles around, because at some point a double which was meant to stand for "Speed" will mistakenly be passed to a function which expected a double that was meant to stand for "FuelConsumption", and all kinds of funny things will happen then. Good luck with debugging a system built this way! With strong typing, the compiler makes sure that you can not do the wrong thing.