Doesnt private members and methods inherently violate the open-closed principle?
Given that private
, protected
and public
modifiers are supported.
I came across this many times in codebases where developers use private
modifiers for members and methods for whatever reason which in turn requires me to copy entire blocks of code to be able to extend it.
I feel like many people just use private
out of habit because its use cases are very nieche in my opinion and almost all the time protected
does the job as well.
9
Thought experiment: imagine a component designed to be OCP-compliant, with certain extension points and public members, so it can be reused in a black-box fashion in several use cases. Imagine also the component has some or several private members.
Now, imagine the private members were all made public – then the same component would still be as reusable as before. So this makes it clear private members – at least technically – don’t contribute to the OCP.
That still does not mean they violate the OCP. Nevertheless you are right – in real-world components, sometimes developers miss occasions for opening a possible extension point to the client by keeping something private, which should be made public. Usually, this involves more than just exchanging the keyword private
by public
, but sometimes this is all what appears to be needed.
However, one should not jump to the conclusion that it is better to make every member public in a reusable component “just in case”. The OCP is usually only one of many goals you have to aim for when designing reusable components. Other typical goals are
-
to keep the component maintainable and evolvable,
-
to keep the number of breaking changes low when creating a new version
-
to keep the API of a component as simple as possible, so another dev has only to learn and understand the 5 public methods to use it and can ignore the 95 private methods which they don’t care for.
And that’s why private members are required – to keep the the impact of changes low, and the whole component comprehensible for a client. That’s especially important when you don’t know all the clients who are potentially reusing your component – by making a method or field private, you signal to them
-
you don’t have to know what this method does when you just want to use this component
-
this part of the code might become subject to change at a later point in time
-
don’t fiddle around with this member from the outside, you may accidentally break some invariant.
Hence, the design of reusable, long-living components is often a trade-off. If one
-
is 100% sure a component’s source code will never-ever become subject to change, not even for a bug fix, and
-
does not care whether a component is used by clients in an anticipated “correct” way, or if clients may shoot themselves in the foot
then one may use only public members. But as soon as you want to provide updates and new releases, you have to find a balance between private and public members.
For inheritance to work well you need to design your base class with inheritance in mind. In that case you should carefully consider what properties and methods should be protected or private, as well as ‘virtual’ or ‘abstract’.
But this is quite a bit of work, so most classes are just not designed for inheritance, and just make everything private. Ideally these should be marked as non-inheritable, but this is unfortunately often not done. Trying to inherit from a class that is not designed for it is likely a poor idea.
I would also recommend avoiding dogmatism, “open/closed principle” is a good idea, but it is possible to get carried away. Just like with all other design patterns you need to know what problem it addresses and where it is applicable.
If you are making an public API it is a very good idea to seriously think about what things users will want to extend, how, and many other design considerations. There is also a trend of Composition over inheritance, so you might want to consider other methods of extending behavior than inheritance.
If you are developing an internal class then you should have a good understanding of how the class is used. So modifications should have a lower cost.
When I make a method private, it means “it’s not designed to be reusable. If you want to reuse it, do it at your own risk and don’t come crying to me if it doesn’t work”.
Open/closed principle doesn’t come for free. Someone has to do serious work to implement it. The original developer said “I’m not paid to do it. And as far as I know, you ain’t gonna need it aka the YAGNI principle.
Now you needed the open/closed principle. And instead of implementing it, as you should have done, you did a copy/paste job, which is one of the worst mortal sins you could have committed. So you have nothing to complain about. Implementing the open/closed principle was your job and you refused to do it.
4
Private methods does not in themselves violate the open-closed principle, but a class with only private methods would violate the principle because such a class is not extensible.
Your problem with having to copy-paste code points to a more fundamental problem with the open-closed principle, and the reason the principle have largely been abandoned for real-world development. (The principle mostly only exist in academia and teaching at this point).
The fundamental problem is: It is not possible to design a class to be extensible for any purpose. Extensibility have to be deliberately designed. The open-closed principle can only really be followed if the the general purpose of the extension was already predicted when the class was designed.
10
Open close principle states to be open for extension while closed for modification. Are private fields and methods visible while extending? No? Then the answer to…
Do private members/methods inherently violate the open-closed principle?
is no.
When extending a model developed by another author that isn’t reachable any further figure scenarios that support the purpose of used access modifiers and when those scenarios are different than what is intended for the future implementations redesign the implementation following whatever principles are intended to follow without considering them. Most of the times while redesigning the redesigned implementation gets lost almost entirely.
developers use private modifiers for members and methods for whatever reason
Is common to use private
access modifier for methods that are implemented to reduce the size of a lengthy complex method under the recommendation that methods should have at most three to five lines of code. I don’t have an answer for the question “where afore mentioned recommendation sources from?” although I’ve noticed it mentioned often.
The argument for private fields is that by changing their values in a derived class you modify the functionality of the original class.
eg.
class Reactor
{
public int temp;
public void AdjustCoolingRods()
{
if(temp > 100) { raiseRods() }
else { lowerRods() }
}
}
class MyReactor : Reactor
{
public void PlayWelcomeMessageOnBoot()
{
temp = 0;
}
}
Clearly by making temp private we protect the AdjustCoolingRods function against modified behaviour
So its the “Closed” part of the Open Closed principle which the private access modifier is complying with.
I’m basing this largely off OCP: The Open-Closed Principle : Robert Martin
Make all Member Variables Private. This is one of the most commonly
held of all the conventions of OOD. Member variables of classes should
be known only to the methods of the class that defines them. Member
variables should never be known to any other class, including derived
classes. Thus they should be declared private, rather than public or
protected. In light of the open-closed principle, the reason for this
convention ought to be clear. When the member variables of a class
change, every function that depends upon those variables must be
changed. Thus, no function that depends upon a variable can be closed
with respect to that variable.
6