I am currently reading Code Complete where McConnell strongly encourages making all variables private. Coincedentally I just so happened to be working on a project where I needed to change a private variable.
The class had a private variable (a String
) telling it where to load an image from to use in the system chrome. I needed to change this image, I do not know about other languages but as far as I know in Flex/AIR, there is no way to override a private variable.
If it had been declared protected, I could have simply extended the class, and overridden that variable. But since it was private, I had to copy all the code from the class and create a duplicate class with the only difference being that string.
I think the argument is to use private as it makes for looser coupling between super and subclasses, however I had to completely violate DRY to be able to achieve a simple string change, which seems to me as worse.
This makes me think that protected is better than private. However, I want to do things the right best-practices way. So if private is better, I want to understand why.
If the general consensus is that private is better, can someone explain why?
In this case, the location of that image used to be a private, implementation-specific feature of the base class. Your new requirements meant that it needed to be able to vary from one derived class to another.
You should keep the member field private, but define a protected virtual property to expose it to derived classes:
private const string _defaultImagePath = @"C:\whatever.bmp";
protected virtual string ImagePath {
get {return _defaultImagePath;}
}
In the derived class that wants to change it:
private const string _myImagePath = @"C:\other.bmp";
protected override string ImagePath {
get {return _myImagePath;}
}
You will also want to change the base class so that it uses the property when it needs the image path, instead of using the field. This is the "Encapsulate Field" refactoring.
Make variables private
for when you know only that the particular class they are defined in will be the only one making use of those variables. However, if you're looking to extend a class, you should be using protected
. Private is really so that you are not using variables globally (so you make use of getters and setters in classes) which helps loosen coupling. Protected is perfectly acceptable when extending a class.
In general, I'd say use the access type that most hides the variable from outside classes and/or packages.
If it had been declared protected, I could have simply extended the class, and overridden that variable. But since it was private, I had to copy all the code from the class and create a duplicate class with the only difference being that string.
And if there had been a setter for the image location, you wouldn't have needed a subclass (or a new class) at all.
And if instead of wanting to change the image, you'd wanted some other minor change, then perhaps making some other API protected/virtual may have helped. Or perhaps not. My only point is that it's hard to look at once nebulous example like this and derive general wisdom from it.
There's a trade-off between how much flexibility a class gives you in terms of its behavior and extensibility, and how much effort it takes to design and test the class (and further interactions among how understandable, well-documented, etc. the class is). These design trade-offs cannot be evaluated in a vacuum, rather they must be evaluated in context. How likely are the various features/behaviors/extensions/changes that a class could possibly support actually going to be? The well-designed class is one that has extensions for common necessary scenarios and lacks unnecessary extensions and APIs. (And for the extensions that are there, there's a choice between simple 'setters' and more complex protected/virtual/subclassing extensibility... the latter is not a trade-off to opt into lightly.)
I don't know that this answers your specific question well (or at all), but the way I read your question, it made me feel like you were implying that "it's better for classes to be swiss-army-knives because extensibility/customizability is good", and I wanted to call out that these 'good' things come with trade-offs. Also, your question seemed to imply that this situation was about 'private' versus 'protected'-and-'subclassing', whereas I think a simple 'setter method' would be a sufficient API change.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With