Exploring SOLID Principles in .NET Core Applications — part 2

Abiodun Maborukoje
3 min readSep 24, 2023

--

New to .NET Core development? Let’s delve into SOLID principles to enhance your coding skills. This is part two of a series of five see the previous part here

Open-Closed Principle (OCP)

The Open-Closed Principle (OCP) states that software entities (such as classes, modules, and functions) should be open for extension but closed for modification. In other words, you should be able to extend the behaviour of a module without changing its source code. You can achieve this by using interfaces and abstraction. Here’s an explanation along with code samples that first violate the OCP and then adhere to it.

Explanation:

  • Violating OCP often results in making changes to existing code when you need to add new functionality.
  • Adhering to OCP means that you design your code in a way that allows you to add new features or behaviours by extending existing classes or modules, rather than modifying them.
  • Interfaces and abstraction play a key role in achieving OCP because they provide a way to define contracts and allow new implementations to adhere to those contracts without altering existing code.

Violation of OCP (Without Abstraction): In this example, let’s assume we have a NotificationService class that sends email notifications. Later, we need to add SMS notifications, but without using abstraction:

// Violating OCP: Modifying the existing class for adding SMS notifications.

public class NotificationService
{
public void SendEmailNotification(User user, string message)
{
// Logic to send an email notification to the user
Console.WriteLine($"Email sent to {user.Email}: {message}");
}

// Violation: Modifying the class to add SMS notifications
public void SendSmsNotification(User user, string message)
{
// Logic to send an SMS notification to the user
Console.WriteLine($"SMS sent to {user.PhoneNumber}: {message}");
}
}

In the code above, we’ve violated OCP because we had to modify the existing NotificationService class to add SMS notifications. This can lead to issues if more notification types are added in the future.

Adhering to OCP (Using Abstraction): Now, let’s refactor the code to adhere to OCP by introducing an abstraction (interface) for notifications:

// Adhering to OCP: Using abstraction (interface) for notifications.

public interface INotification
{
void Send(User user, string message);
}

public class EmailNotification : INotification
{
public void Send(User user, string message)
{
// Logic to send an email notification to the user
Console.WriteLine($"Email sent to {user.Email}: {message}");
}
}

public class SmsNotification : INotification
{
public void Send(User user, string message)
{
// Logic to send an SMS notification to the user
Console.WriteLine($"SMS sent to {user.PhoneNumber}: {message}");
}
}

In this refactored code:

  • We’ve introduced an INotification interface that defines the contract for sending notifications.
  • We’ve created separate classes (EmailNotification and SmsNotification) that implement this interface for email and SMS notifications, respectively.
  • Now, you can easily add new notification types (e.g., PushNotification) without modifying existing code. This adheres to the Open-Closed Principle because you can extend the system without altering the existing classes.

By using abstraction and adhering to OCP, you make your code more flexible and maintainable, enabling you to add new features without the risk of breaking existing functionality.

Click here for part — 3

--

--

Abiodun Maborukoje

A seasoned Software Engineer with years of experience specializing in crafting advanced software solutions.