Open closed principle
Asked Answered
S

1

5

I understand that this principle states that a module is open for extension but closed for modification, and this is clear when we want to upgrade/modify a method in some class - we create another class that inherits the base class and then override the base method here in order to keep both functionalities.

But how about the case when we want to add another different method to the base class? Is this considered as modification or extension of the base class - is ok to add the method to the base class or we should also create new class that inherits the base class and then put new method there?

Also, same question for adding properties and fields to the base class.

Softcover answered 28/6, 2017 at 8:19 Comment(9)
Is there an option to make the amendment to the interface instead? And to answer your question - I'd regard that as a change and not extension. As for methods, have you considered extension methods, that by definition are extending the original functionality?Midriff
What the open closed principle really means, is that when you want to added more functionality to a process, you shouldn't have to change the original process.Reference
@Konrad Viltersten I may be wrong, but I thought that extension methods are preferred only if you want to extend the functionality of the class that you don't own.Softcover
I understand OCP as follows: your system should be designed the way that if you want to extend it, you write new code instead of rewriting old codeExosmosis
I disagree with the close votes that claim this question is opinion based. We are discussing a well established SOLID principle, and whether or not a certain action violates this principle. That is not an opinion.Uniaxial
What does this method do? What is the responsibility of the base class and what is the responsibility of the child class? You can't apply blanket design rules without context. There are circumstances where adding this method (etc) is valid and others where it's not. This may be because of the OCP though the Single Responsibility Principle is important here too.Bala
@Uniaxial There's always a number of users who rather assume that it's opinion-based material unless they feel otherwise. I've been into discussion in that regard numerous times. Often with infected outcome pointing out that community decision is to close it. (Interestingly, in case the community decision reopened the issue, the same individuals questioned the process. Hence the infected part, hehe.)Midriff
i guess first you gotta understand inheritance, is the new method relevant to all classes / specialisations or is it specific to a single specialisation ? this would tell you where to put it. Secondly adding another method to base class should be considered extension and not modification in my opinion as you're not changing the inner workings of existing code but introducing new stuff . This new function is relevant to all subsWhiskey
Well, yes it is definitely relevant to the base class only and this is mainly why I was in doubt. I wanted to put it in base class in order to comply to single responsibility principle.Softcover
U
6

TL;DR
I think adding a new method inherently means that you cannot violate OCP; as OCP mainly focuses on the reckless overriding of existing methods.


Example:
Base class Calculator is inherited by MyCustomCalculator. The base class only has methods for adding, subtracting, multiplying and dividing two numbers.
Creating a new method in MyCustomCalculator, e.g. CalculateAverage(params int[]) does not violate OCP. It does not modify the logic behind any of the existing methods, it merely extends the methods that are provided by the calculator object.

New methods inherently do not change the old methods. Therefore, they don't modify existing logic; then simply extend what is available.

So no, it does not (inherently) violate OCP.

It's almost impossible for it to violate OCP, as creating something new is (inherently) completely different from modifying something that exists.


Some things to take note of though:

  • I can think of one (arguable) exception to this: overloading. If you create a new method that overloads an existing one, then you are responsible to abide by the rules of overloading. Most notably, this means that overloaded methods should perform the exact same task as eachother (overloaded methods are simply based on different input parameters, but their processing and output should be functionally equivalent). Although I am not 100% sure if this is a violation of OCP (because it wrongly extends a base class), or SRP (because it creates an ambiguous responsibility as to the processing/output of the overloaded methods). It seems like a bit of both.
  • The same principle applies even if your new method does not overload an existing one. Is the new method relevant enough to the responsibility (intention/purpose) of the base class? Because if it is very different, then you might be violating SRP.

EDIT

I missed part of your question

is it ok to add the method to the base class or we should also create new class that inherits the base class and then put new method there?

That depends on context. For the Calculator / MyCustomCalculator / CalculateAverage() example I provided; I would instinctively add it to the base class, as calculating averages is a basic operation that pertains to the responsibilities of a calculator.

However, if we were discussing adding a method that only pertains to complex numbers (MethodForComplexNumbers()), then I would advocate the creation of a ComplexNumberCalculator which inherits from Calculator and implements MethodForComplexNumbers().

However, I think this is mainly due to SRP, not OCP.

Uniaxial answered 28/6, 2017 at 9:28 Comment(6)
Might be worth to discuss a few corner cases: For example, if a class is involved in any sort of (de-)serialization, then adding to the class can be enough to break existing serialized data.Hereabout
@grek40: Are you sure? Because deserialization of data should only really try to set the properties that it finds in the serialized data. As long as those properties are still present in the class, it shouldn't care about additional properties that you've added. Especially since serialization requires a parameterless constructor, any properties that are not being set should already have a workable default value. (also, in general, SOLID tends to fall apart in fringe cases. It's a good guideline, but not a good global law).Uniaxial
@grek40: The only issue that I see would be with serializing the updated class, and then trying to deserialize it with an outdated version. But that's a problem that's inherently impossible to avoid, barring some excessive try/catch logic (which I'm not a proponent of)Uniaxial
Surely, a good mannered serializer would just ignore extra data... but even though C# has less of those pitfalls than other languages, there are still things like the binary formatter lingering around, requiring you to fulfill their special needs in order to not break things. As said, this is a corner case and not a main usage scenario. Another little more common example: consider an UI table with autogenerated columns - UI will change just by extending the data item class with additional properties.Hereabout
Any change is a trade-off with possible side effects that might appear in combination with reflection - in the end the developer has to decide if those things are an actual concern for the case at hand. It would be invalid to state a general rule of extending is not critical without any limitation.Hereabout
@grek40: I'm not saying you're wrong (binary serialization is a good example), but it seems to go out of scope as far as SOLID is concerned. SOLID has no bearing on existing saved data. SOLID only focuses on good practices within reason. I've never seen any project (other than small examples) that fully adhere to SOLID principles to a pedantic degree. You pass a point where the effort of its implementation is no longer worth the benefit you gain from doing so.Uniaxial

© 2022 - 2024 — McMap. All rights reserved.