0% found this document useful (0 votes)
20 views

SOLID — Open-Closed Principle (Part 2) _ by Matthias Schenk _ Towards Dev

Uploaded by

alok singh
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
20 views

SOLID — Open-Closed Principle (Part 2) _ by Matthias Schenk _ Towards Dev

Uploaded by

alok singh
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 5

12/21/24, 8:43 PM SOLID — Open-Closed Principle (Part 2) | by Matthias Schenk | Towards Dev

SOLID — Open-Closed Principle


(Part 2)
Matthias Schenk · Follow
Published in Towards Dev · 5 min read · Jun 23, 2023

In the last article I started my series about the SOLID principles. The first
part was dedicated to the Single Responsibility Principle. Today I want to
continue with the next principle, which stands behind the O of the acronym.

What is the Open-Closed Principle?


The Open-Closed Principle (OCP), characterized by Bertrand Meyer, is a key
principle in object-oriented programming. It states that software entities
(classes, modules, functions, etc.) should be open for extension but closed for
modification. In other words, the behavior of a module or class should be
extendable without requiring changes to its existing code. This principle
forces developers to design software that can be easily modified and
extended to implement new requirements or features.

The advantages that OCP brings to your application are similar to the ones of
the Single Responsibility Principle but for different reasons.

Maintainability: When code is closed for modification, it reduces the risk


of introducing bugs or breaking existing functionality when new code is
written. I can confidently extend the code by adding new features
without worrying about impacting the existing functionality, that is
already tested. This makes maintenance and bug fixes more
straightforward and less error-prone.

Scalability: The Open-Closed Principle promotes a modular approach to


development. By designing code that is open for extension, adding new
features becomes a matter of extending existing modules or creating new
ones. This modular structure allows the system to scale effortlessly as

https://towardsdev.com/solid-open-closed-principle-part-2-ed1bdc5a2326 1/7
12/21/24, 8:43 PM SOLID — Open-Closed Principle (Part 2) | by Matthias Schenk | Towards Dev

new requirements are coming. It makes working in parallel on code


easier because the risk of conflicts is manageable.

Reusability: Code that is open for extension leads to the creation of


reusable components. By designing modules and classes that are closed
for modification, they become self-contained and can be easily reused in
different parts of the system. Reusability not only saves development
time and effort but also ensures consistent behavior across various
codebases.

Testability: Closed code is easier to test because its behavior is well-


defined and isolated. By following the Open-Closed Principle, developers
can write unit tests for specific modules or classes, ensuring that their
functionality is correct and independent of other parts of the system. As
new features are added through extension, they can be tested in isolation
without affecting existing tests.

Now that the advantages of the Open-Closed Principle are described in


theory, let’s have a look on it in a practical example.

Example
To show the Open-Closed Principle in action, let’s consider an example of a
messaging application that supports multiple messaging services such as
SMS, Email, and Push Notifications.

The first version will be one that clearly violates the principle in order to
show the problems that will arise:

class MessagingClient {
fun sendNotification(service: String, message: Message) {
when (service) {
"SMS" -> {
// Send SMS
}
"Email" -> {
// Send Email
}
"PushNotification" -> {
// Send Push Notification
}
else -> {
throw IllegalArgumentException("Invalid service")
}
}
}
}

In the above example, the MessagingClient class contains a sendNotification0


— method that takes the name of the messaging service as a parameter.
Based on the service name, the method performs the corresponding
message sending logic.

What are the problems with this implementation approach?

https://towardsdev.com/solid-open-closed-principle-part-2-ed1bdc5a2326 2/7
12/21/24, 8:43 PM SOLID — Open-Closed Principle (Part 2) | by Matthias Schenk | Towards Dev

Maintenance Nightmare: Every time a new messaging services is


introduced or one of the existing services need to be modified, the
MessagingClient class needs to be modified. This violates the Open-Closed
Principle, as the class is open for modification. Any change in one part of
the code could have a cascading effect on other parts, making the system
fragile and error-prone.

Code Duplication: If the same or similar logic is required in multiple


places within the codebase, the risk of duplicating code is rising. In the
given example, if the logic for sending SMS is needed in another part of
the system, it would need to be replicated. This duplication increases the
risk of introducing inconsistencies and makes code maintenance more
challenging.

Scalability Issues: Adding a new messaging service requires modifying the


MessagingClient class, introducing a tight coupling between the client and
the specific messaging service. This makes the system less scalable, as
each new service addition makes changing existing code necessary,
rather than extending it. The development process becomes slower and
more error-prone, limiting the system's ability to adapt to evolving
requirements.

Testing Complexity: The tight coupling between the MessagingClient class


and specific messaging services makes testing more complex. Unit tests
for the client need to account for the different branches of the when —
statement, potentially increasing the number of test cases. Additionally,
changes to one service's implementation could impact the tests of other
services, leading to a fragile test suite for the class. Because the
connection to external systems are created inside the class it is not
possible to replace them by mocks or test doubles in test scope.

I think it is clear now, why the above solution is not a good one, so I will
change the design of the system to make adding new messaging services,
without modifying the existing code, possible.

I start by creating an interface that defines the common behavior for all
messaging services. This abstraction acts as the contract that all concrete
messaging services must fulfill.

interface MessagingService {
fun sendMessage(message: Message)
}

The MessagingService interface provides a template for sending messages but


leaves the specific implementation details to its subclasses. Each subclass
will provide the specific logic for sending messages using the respective
messaging service.

https://towardsdev.com/solid-open-closed-principle-part-2-ed1bdc5a2326 3/7
12/21/24, 8:43 PM SOLID — Open-Closed Principle (Part 2) | by Matthias Schenk | Towards Dev

class SmsService : MessagingService() {


override fun sendMessage(message: Message) {
// Implement SMS-specific logic
}
}

class EmailService : MessagingService() {


override fun sendMessage(message: Message) {
// Implement email-specific logic
}
}

class PushNotificationService : MessagingService() {


override fun sendMessage(message: Message) {
// Implement push notification-specific logic
}
}

To decouple the code that uses the messaging services from the specific
implementations, I can use polymorphism and dependency injection. This
allows me to switch between different messaging services without modifying
the client code.

Lets consider the following example of a MessagingClient class that relies on


a specific messaging service to send notifications.

class MessagingClient(private val messagingService: MessagingService) {


fun sendNotification(message: Message) {
messagingService.sendMessage(message)
}
}

The MessagingClient class takes an instance of MessagingService through its


constructor, using dependency injection to ensure flexibility and reusability.
It provides a method sendNotification that delegates the actual message
sending to the injected messaging service.

To add a new messaging service, I can simply create a new class that extends
MessagingService and implements the required methods. I can then inject the
new service into the MessagingClient without modifying the existing code:

class SlackService : MessagingService() {


override fun sendMessage(message: Message) {
// Implement Slack-specific logic
}
}

val messagingClient = MessagingClient(SlackService())


messagingClient.sendNotification(Message.from("New message on Slack"))

Conclusion
The Open-Closed Principle is a fundamental principle in software
development that promotes code that is open for extension but closed for
modification. By designing software components that care about this
https://towardsdev.com/solid-open-closed-principle-part-2-ed1bdc5a2326 4/7
12/21/24, 8:43 PM SOLID — Open-Closed Principle (Part 2) | by Matthias Schenk | Towards Dev

principle, I can achieve code that is more maintainable, scalable, reusable,


and testable. In this article, I explored OCP using a simple but clear
examples, demonstrating how to design a messaging system that enables for
adding new messaging services without modifying existing code. By caring
about this principle, it helps me to build robust and adaptable software
systems that can evolve and grow with changing requirements.

In the next part of this series I will talk about the Liskov Substitution
Principle.

Software Development Software Architecture Principles Clean Code

Published in Towards Dev Follow


5.1K Followers · Last published 1 day ago

A publication for sharing projects, ideas, codes, and new theories.

Written by Matthias Schenk Follow


471 Followers · 27 Following

Kotlin | Java | Spring Ecosystem | Software Craftsman

No responses yet

What
are
your
thoughts?

Respond

More from Matthias Schenk and Towards Dev

https://towardsdev.com/solid-open-closed-principle-part-2-ed1bdc5a2326 5/7

You might also like