difference between open closed principle and inheritance
Asked Answered
E

3

5

I know that open closed principle mean open for extension and closed for modification. Consider an example as follows

public class Vehicle{
    public void service(){
        //vehicle servicing code
    }
}

public class Bike extends Vehicle{

    public void service(){
        // bike specific servicing 
    }
}

Now I understand that Bike class has extended Vehicle and adds new functionality using Open Closed Principle.

Consider I create jar file of Vehicle class and then Bike class extends Vehicle class from jar. In this case, we can't modify Vehicle class and Bike extends it. Is it a good example of open closed principle? I would like to know how OCP is different from inheritance

Elyot answered 7/4, 2015 at 17:54 Comment(0)
C
1

OCP is not different from Inheritance, rather the "Open" part of the OCP is open for extension, but should be closed for modification. I.e. the code should only modified for errors/bugs but for new extension or change to the functionality it should be extended.

As a Side note I believe this would be better put in the programmers.stackexchange.com site.

Conscious answered 7/4, 2015 at 18:30 Comment(2)
Consider I create jar file of Vehicle class and then Bike class extends Vehicle class from jar. In this case, we can't modify Vehicle class and Bike extends it. Is it a good example of open closed principle?Elyot
I would say to make it a bit more clear, Say you have a Vehicle Class and you even create a Car class and both of them define how you service them. And now you release this as a jar, if someone comes with a Bike or even a specific car say Lamborghini that has a specific service requirement, you would have to extend the Car class or Vehicle class to "add" this functionality.Conscious
B
10

Here is my opinion on interpreting OCP:

OCP points out that code can be categorized based on how often it changes, and various parts of "same" code can have different frequencies of change, and by change I mean not only change over time but also change in runtime - e.g. selecting this or that particular piece of code to perform some action.

OCP requires that the more stable code be separated from the one that is more likely to change. But it does not stop there, it also demands that the less frequently changing code be able to work with the one more frequently changing.

So is OCP == inheritance? No. Inheritance is just one of the techniques used to fulfill OCP. Strategy pattern, decorator pattern, ordinary composition, parametric polymorphism (aka generics), and other techniques can be used to achieve those goals too.

Example of what I mean by different frequencies of change. Let's imagine some collection implementation. Wouldn't it be awful, if each time some primitive type is added to the language, the collection code needed to be updated too? So collections treat items they hold as opaque, thus fulfilling OCP. Next example, let's take that same collection implementation from the previous example, and imagine that we want to print it's elements sorted. Simple. We will just add sort to a collection.... and 10 other collection types? And every new collection will have to implement that sort too? Awful. Wouldn't it be better if our sort algorithm just treated collection as opaque type, that if asked will supply it's items serially? That's only thing our sort need collection to do, and once given list of elements, it can do actual sorting. Ok. So now the collection just needs to have to support an operation that serially returns all items. Easy... And if we think about it, it's quite a useful behavior that could be used in filtering, transformations, ....

Hopefully, with above example I showed some OCP usage beyond inheritance, and showed that the OCP also encourages us to view our code as composition of different levels of abstraction (composition of code with different frequencies of change).

Biamonte answered 12/3, 2018 at 6:54 Comment(0)
C
1

OCP is not different from Inheritance, rather the "Open" part of the OCP is open for extension, but should be closed for modification. I.e. the code should only modified for errors/bugs but for new extension or change to the functionality it should be extended.

As a Side note I believe this would be better put in the programmers.stackexchange.com site.

Conscious answered 7/4, 2015 at 18:30 Comment(2)
Consider I create jar file of Vehicle class and then Bike class extends Vehicle class from jar. In this case, we can't modify Vehicle class and Bike extends it. Is it a good example of open closed principle?Elyot
I would say to make it a bit more clear, Say you have a Vehicle Class and you even create a Car class and both of them define how you service them. And now you release this as a jar, if someone comes with a Bike or even a specific car say Lamborghini that has a specific service requirement, you would have to extend the Car class or Vehicle class to "add" this functionality.Conscious
H
1

Problem: without Inheritance

Let's build an example based on the given code in the question. Different vehicles are serviced in a different manner. So, we have different classes for Bike and Car because the strategy to service a Bike is different from the strategy to service a Car.

The Garage class accepts various kinds of vehicles for servicing. Observe the code and see the how the Garage class violates the open-closed principle:

class Bike {
    public void service() {
        System.out.println("Bike servicing strategy performed.");
    }
}

class Car {
    public void service() {
        System.out.println("Car servicing strategy performed.");
    }
}

class Garage {
    public void serviceBike(Bike bike) {
        bike.service();
    }

    public void serviceCar(Car car) {
        car.service();
    }
}

As you might have noticed, whenever some new vehicle like Truck or Bus is to be serviced, the Garage will need to be modified to define new methods serviceTruck() and serviceBus(). That means the Garage class must know every possible vehicle like Bike, Car, Bus, Truck and so on. So, it violates the open-closed principle by being open for modification. Also it's not open for extension because to extend the new functionality, we need to change it.


Solution: with Inheritance

Abstraction

To solve the problem in the code above and satisfy the open-closed principle, we need to abstract the implementation details of the servicing strategy for each type of vehicle. That means we need abstraction of Bike and Car classes.

Polymorphism

We also want the Garage class to accept many forms of the vehicle, like Bus, Truck and so on, not just Bike and Car. That means we need polymorphism (many forms).

Inheritance

So, for satisfying the open-closed principle, the most important mechanisms are abstraction and polymorphism. In statically typed languages such as Java, C# etc. the important tool that provides abstraction and polymorphism is inheritance.

To abstract the implementation details of the servicing strategies for various types of vehicles we use an interface called Vehicle and have an abstract method service().

And for the Garage class to accept many forms of the Vehicle, we change the signature of its method to service(Vehicle vehicle) { } to accept the interface Vehicle instead of the actual implementation like Bike, Car etc. We also remove the multiple methods from the class as just one method will accept many forms.

interface Vehicle {
    void service();
}

class Bike implements Vehicle {
    @Override
    public void service() {
        System.out.println("Bike servicing strategy performed.");
    }
}

class Car implements Vehicle {
    @Override
    public void service() {
        System.out.println("Car servicing strategy performed.");
    }
}

class Garage {
    public void service(Vehicle vehicle) {
        vehicle.service();
    }
}

Closed for modification

As you can see in the code above, now the Garage class has become closed for modification because now it doesn't know about the implementation details of servicing strategies for various types of vehicles and can accept any type of new Vehicle. We just have to extend the new vehicle from Vehicle interface and send it to the Garage. We don't need to change any code in the Garage class.

Another entity that's closed for modification is our Vehicle interface. We don't have to change the interface to extend the functionality of our software.

Open for extension

The Garage class now becomes open for extension in the context that it will support the new types of Vehicle, without modifying.

Our Vehicle interface is open for extension because to introduce any new vehicle, we can extend from the Vehicle interface and provide a new implementation with a strategy for servicing that particular vehicle.


So, as you can see, the inheritance is a just tool provided by the programming languages that we use for abiding by the open-closed principle rules.

That's it! Hope that helps.

Huda answered 25/10, 2020 at 16:29 Comment(1)
In statically typed languages such as Java, C# etc. the important tool that provides abstraction and polymorphism is inheritance. Well, as a c++ programmer I prefer to use templates: struct Garage { template <typename Vehicle> void service(Vehicle & v) {v.service();} };. Even in C we use void * to get around this issue. Templates/duck typing means we basically never need to use inheritance to avoid repetition/dependencies, etc.Tanning

© 2022 - 2024 — McMap. All rights reserved.