3

Just a quick one, so following the open closed principle, if you had a class like so:

public class Employee extends Person {
    int age;
    String name;

    Employee(int age, String name) {
        super(age, name)
    }
    
    // Getters and setters follow
}

If you wanted to add an additional field, let's say an address, wouldn't this be breaking the Open/Closed principle?

Just curious if you are breaking that principle doing that, how would you create the class to work around this issue?

Thanks

MaxCulley
  • 59
  • 1
  • 8

2 Answers2

4

The short answer is "yes". It would be a violation of OCP. So, to answer your question (how would you create the class to work around this issue), Let's see what OCP is first:

Open/Closed Principle

OCP states that software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification.

You clearly understand the last part, but you appear to miss on the first part. Again, the short answer to your question is to simply extend your original class.

public class Person {
   int age;
   String name;
   // rest of class omitted
}

// This class already obeyed OCP by extending Person and adding new attributes and behaviors (took the liberty to change your original class for a good reason - See Person class)
public class Employee extends Person {
   String empID;
   // Rest of the class omitted
}

// Simply add one more (corny class name, sorry)
public class AddressableEmployee extends Employee {
   private String address;
   // Rest of the class omitted
}

This is how to obey OCP when adding new functionality. Obviously, if this is abused, it leads to class explosion which is also bad. As a developer (and designer) you must weight blindly respecting this principle against creating deep hierarchical chains.

The thing to remember is that OCP (as the rest of SOLID) are simply recommendations. Lastly, if you find yourself in this situation, it might be an indicator of hasty design decisions (went straight to implementation without taking adequate time to solidify your design). So, instead of taking another hasty implementation decision, stop and consider redesigning what you created originally (i.e. consider composition over inheritance).

hfontanez
  • 5,774
  • 2
  • 25
  • 37
  • 1
    Yes. Always consider refactoring before adding layers of crud (not CRUD :-)... you'll eventually have to refactor or rewrite anyway if you don't, and it will be more painful and expensive later. – Jim Garrison Jan 28 '21 at 18:53
  • 1
    Ahhh okay, so something is big enough to warrant a change, you shall just have a new class that extends the current. Perfect description, thank you so much :) – MaxCulley Jan 28 '21 at 19:28
  • Instead of editing my answer, I will simply comment that with this "solution", now you have a problem with Liskov Substitution Principle. This goes to the heart of my answer: STOP and reevaluate BEFORE implementing a solution. – hfontanez Jan 28 '21 at 19:28
2

The short answer is "yes". And @hfontanez gives a good high-level introduction to the OCP, which you would see echoed in most of the OCP-related answers on SO.

But the long answer is "no". Because the OCP doesn't apply here.
To understand what kind of scenario we need to worry about the OCP, we must start from the appropriate programming paradigm. The OCP, like all the SOLID principles, is object-oriented. It applies to object-oriented code.

Employee is not an object, in the OO sense of the word, because objects have behavior. Employee is a data structure: it is purely a representation of state. Data structures are foundational to both procedural as well as functional programming, but not OO. Trying to apply the OCP to Employee sets us on the wrong track from the start, because we're in the wrong paradigm.

Solving the paradigm issue may seem trivial. We can just implement a doWork() method in Employee and then we've got some behavior, right? But this is where the SOLID principles begin to interact. Because who is going to call that doWork() method? Certainly not any client outside of the Employee module! After all, Employee is a concrete implementation, and the Dependency Inversion Principle prescribes dependencies on abstractions, not concretions.

Again, we might reach for a trivial solution. Extract the doWork() method to an interface implemented by Employee. Now clients can invoke it while obeying the DIP. (And since we're considering the interaction of SOLID principles, also assume the implementation of doWork() obeys the contract of its abstract declaration, so that we do not violate the LSP.)

Certainly now the OCP applies to Employee, right? It has both state and behavior (making it a full-fledged, OO object) and it exposes its behavior through an appropriate abstraction. But the OCP still does not apply... because Employee is now an implementation detail. The definition of being "closed" according to the OCP includes being published for use by clients (i.e. public). Implementation details are not part of this definition.

So through a combination of SOLID principles, we reach an important conclusion.

The OCP applies strictly to the public, abstract, API of an object-oriented application or library.

Feel free to edit your implementation details at will. The OCP doesn't mind.

jaco0646
  • 15,303
  • 7
  • 59
  • 83
  • Great point!! There are two things in play here and I wish I would've provided a more detailed answer to this question. The first point, "Employee" is a role a "Person" has. As such, the "Employee" behavior should be injected, not enforced by inheritance. The second point is that if your design is flawed to begin with, modifying a bad implementation is not just OK, it's actually the best thing to do. It makes no sense to have this attitude of "SOLID or bust" simply to say that I followed SOLID principles. – hfontanez Sep 20 '21 at 13:15
  • In fact, to continue my previous point, creating an "Employee" class that inherits from "Person" is REALLY BAD design. Why? How would you be able to handle a "Person" that retires or is fired and stays unemployed for some period of time? You won't be able to do it. – hfontanez Sep 20 '21 at 13:18