L B wrote: |
---|
@Disch in ChessPlusPlus we are using instances of classes that extend the Configuration class based on the thing using them (e.g. BoardConfig, GraphicsConfig) and different instances correspond to different loaded config files (currently only one config file, but mods might need more). |
Thanks for this. That's definitely a good use case for inheritance and modularity (not having a singleton). I can definitely see the value in that.
But when it comes down to individual config options within the GraphicsConfig class.... do you write getters/setters for all of them?
In this situation I really don't see a "configuration" being a single entity apart from how it's stored. Does any one config option depend on the status of another? Are any of them interconnected in any way?
cire wrote: |
---|
If at any point in time you want to change your Point class to have a different internal representation (say, from cartesian to polar coordinates or from absolute to relative coordinates) |
Vectors, by definition, are always relative.
And changing internal representation from cartesian to polar coordinates is a big enough change that it would
demand the interface be changed or else performance would tank. Doing trig calls for every setX() function... then again for every setY() function would be completely unacceptable in nearly all practical applications. (yes you could get around that postponing the trig calls until they're absolutely necessary, but that is a whole other can of worms I won't get into).
Furthermore, many common mathematical functions that vectors are used for rely on it being in cartesian coordinates (*cough*dot product*cough*).
And lastly, even if you had a need to work in polar coordinates after a long-standing cartesian system... a better solution would be to create an entirely different PolarVector struct, and have (explicit) ctors to convert between the two.
cire wrote: |
---|
one doesn't (necessarily) need to modify the interface. This is true for any type. |
I would disagree. Some types are so fundamental that their direct access
is their interface. Granted this is not common by any meaning of the word... but it certainly exists.
I wouldn't say my 'config options' example would qualify... but a Vector certainly would.
Just because one can't see the need for changing it now, doesn't mean the need won't arise in the future. |
There is truth to this... and I'm certainly in favor of writing code that is adaptable and expandable. However there are limits. At some point you have to say "This is what this class does".
It is literally impossible to plan ahead for every conceivable change down the line. To even attempt to do so invites increasingly obfuscated code and stifles productivity.
Case in point, in an little indie group project I'm working on... one of the teammates was writing a class to manage a relatively simple task. We gave him the requirements of what we needed the class for and how it was going to be used. ~4 days later he comes back with a huge hierarchy of templates. Maybe 6 or 7 classes, well over 1000 lines, and code so dense nobody else wanted to deal with it.
When I looked through the code and started asking him Qs about it... like "Why did you do X?", the answer was typically "it would be useful if we need to do Y with the class". ... But we didn't need to do Y with the class.
Anyway long story short... we scrapped the stuff he wrote and someone else on the team spent half a day (vs 4 days) to write a ~150 line class that did what we needed.
TL;DR
The moral here is... be flexible... but also be reasonable. Don't let an endless stream of "what ifs" force to you write obfuscated code.