I am bit confused about how Open Closed principle can be applied in real life. Requirement in any business changes over the time. According to Open-Closed principle you should extend the class instead modifying the existing class. To me every time extending a class does not seem to be practical to fulfill the requirement. Let me give an example with train booking system.
In train booking system there will be a Ticket object.There could be different types of tickets Regular Ticket, Concession Ticket etc. Ticket is abstract class and RegularTicket and ConcessionTickets are concrete classes. Since all the tickets will have PrintTicket method which is common, hence it is written in Ticket which is base abstract class. Let's say this worked fine for few months. Now new requirement comes in, which states to change the format of the ticket. May be few more fields are added on the printed ticket or may format is changed. To fulfill this requirement I have following options
- Modify the PrintTicket() method in Ticket abstract class. But this will violate Open-Closed principle.
- Override the PrintTicket() method in child classes but this will duplicate the printing logic which is violation of DRY(Do not repeat yourself) Principle.
So questions are
- How can I satisfy above business requirement without violating the Open/Closed principle.
- When the class is supposed to be closed for modification? What are the criteria to consider class is closed for modification? Is it after initial implementation of the class or may be after first deployment in production or may be something else.
Best Answer
This depends on the way the
PrintTicket
is implemented. If the method needs to consider information from subclasses, it needs to provide a way for them to supply additional information.Moreover, you can override without repeating your code too. For example, if you call your base class method from the implementation, you avoid repetition:
Template Method pattern supplies a third option: implement
PrintTicket
in the base class, and rely on derived classes to supply additional details as needed.Here is an example using your class hierarchy:
It's not the class that should be closed to modification, but rather the interface of that class (I mean "interface" in the broad sense, i.e. a collection of methods and properties and their behavior, not the language construct). The class hides its implementation, so the owners of the class can modify it at any time, as long as its externally visible behavior remains unchanged.
The interface of the class needs to remain closed after the first time that you publish it for external use. Internal-use classes remain open to refactoring forever, because you can find and fix all its usages.
Apart from the simplest cases, it is not practical to expect that your class hierarchy is going to cover all possible usage scenarios after a certain number of refactoring iterations. Additional requirements calling for entirely new methods in the base class come up regularly, so your class stays open to modifications by you forever.