The Open-Closed Principle “O”
“software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification”.
This principle advocates Inheritance and Polymorphism. The way to achieve this contradictory suggestion is to design loosely coupled classes which bind together using Interfaces or Abstraction.
Functionality can be extended by Inheriting a class OR by providing concrete implementation for an Interface or Abstract class. These can be done without changing anything in the existing classes; in fact existing classes can be in separate library.
Consider this class diagram for Logger:

The class LogManager is defying Open-Closed principle by containing functionalities for logToFile() and logToDB(). In future, there may be a requirement to log messages using webservice call. This new functionality would require changes in existing LogManager class; but it’s bad design if an existing class is modified to add new functionality.
A good design is to have separate classes for logging to File and DB:

The LogManager class doesn’t know how to write a String and it depends on derived classes for writing string. It has log(Object) method to serialize object into string and log(String) abstract method for concrete implementation:
public void log(Object obj) {
String message = serializer.serialize(obj);
log(message);
}
public abstract void log(String msg);
With this design, any new type of logger like web-service or message queue can be added by providing another concrete implementation of LogManager. It will not require any change in the existing classes.
Conclusion
The Open-Closed principle helps in Object Oriented class designing. It enforces Abstraction and increases code reusability.