What is the meaning and reasoning behind the Open/Closed Principle?

后端 未结 14 1086
死守一世寂寞
死守一世寂寞 2020-12-02 08:31

The Open/Closed Principle states that software entities (classes, modules, etc.) should be open for extension, but closed for modification. What does this mean, and why is i

相关标签:
14条回答
  • 2020-12-02 09:10

    Let's break down the question in three parts to make it easier to understand the various concepts.


    Reasoning Behind Open-Closed Principle

    Let's consider an example in the code below. 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.

    Problem of Rigidity

    Observe the code and see how the Garage class shows the signs of rigidity when it comes to introducing a new functionality:

    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 may have noticed, whenever some new vehicle like Truck or Bus is to be serviced, the Garage will need to be modified to define some new methods like 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 modify the class.


    Meaning Behind Open-Closed Principle

    Abstraction

    To solve the problem of rigidity in the code above we can use the open-closed principle. That means we need to make the Garage class dumb by taking away the implementation details of servicing of every vehicle that it knows. In other words we should abstract the implementation details of the servicing strategy for each concrete type like Bike and Car.

    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() in it.

    Polymorphism

    At the same time, we also want the Garage class to accept many forms of the vehicle, like Bus, Truck and so on, not just Bike and Car. To do that, the open-closed principle uses polymorphism (many forms).

    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();
        }
    }
    

    Importance of Open-Closed Principle

    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 the Vehicle interface and send it to the Garage. That's it! 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 the need for 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.

    Strategy Design Pattern

    Did you notice that I used the word strategy multiple times? That's because this is also an example of the Strategy Design Pattern. We can implement different strategies for servicing different types of Vehicles by extending it. For example, servicing a Truck has a different strategy from the strategy of servicing a Bus. So we implement these strategies inside the different derived classes.

    The strategy pattern allows our software to be flexible as the requirements change over time. Whenever the client changes their strategy, just derive a new class for it and provide it to the existing component, no need to change other stuff! The open-closed principle plays an important role in implementing this pattern.


    That's it! Hope that helps.

    0 讨论(0)
  • 2020-12-02 09:11

    Specifically, it is about a "Holy Grail" of design in OOP of making an entity extensible enough (through its individual design or through its participation in the architecture) to support future unforseen changes without rewriting its code (and sometimes even without re-compiling **).

    Some ways to do this include Polymorphism/Inheritance, Composition, Inversion of Control (a.k.a. DIP), Aspect-Oriented Programming, Patterns such as Strategy, Visitor, Template Method, and many other principles, patterns, and techniques of OOAD.

    ** See the 6 "package principles", REP, CCP, CRP, ADP, SDP, SAP

    0 讨论(0)
提交回复
热议问题