SOLID Principles (Part-1)

Ramkumar
4 min readJan 27, 2024

--

Introduction

Imagine a software developer in a world filled with endless apps and programs. They’re busy creating new things, but here’s the thing — are they making sure their creations can handle growth and are easy to take care of?

That’s where SOLID principles come into play. Think of them as rules for good coding. They guide our developers like a wise friend, making sure each part of their code does one thing well, can grow without causing trouble, and fits together smoothly.

SOLID is an acronym for five design principles intended to make object-oriented designs more understandable, flexible, and maintainable.

Single Responsibility Principle

The Single Responsibility Principle (SRP) states that a class or module in software development should have only one reason to change, meaning it should have only one responsibility or job. This principle encourages the creation of smaller, focused, and more maintainable components in a system.

SRP

If a Class has many responsibilities, it increases the possibility of bugs because making changes to one of its responsibilities could affect the other ones without you knowing.

To understand better let’s design a Bird class.

The simplest solution would be to create a Bird class with different attributes and methods. A bird could have the following attributes:

  • Weight
  • Color
  • Type
  • Size
  • BeakType

A bird would also exhibit the following behaviors:

  • Fly
  • Eat
  • Make a sound

The Bird class follows

public class Bird {
private int weight;
private String colour;
private String type;
private String size;
private String beakType;

public void fly() {
...
}

public void eat() {
...
}

public void makeSound() {
...
}
}

Simple we have designed Bird class. But, let’s say based on the bird type the fly method will vary. To understand this let’s implement the fly method.

public void fly() {
if (type.equals("eagle")) {
flyLikeEagle();
} else if (type.equals("penguin")) {
flyLikePenguin();
} else if (type.equals("parrot")) {
flyLikeParrot();
}
}

Now Bird class has another responsibility which is deciding which fly method needs to be called. This code has the following problem.

  1. Readability: The above code is not readable, this would be extremely difficult to read if the fly has many types.
  2. Testing: The above code is not easily testable, we would have to test each bird separately.
  3. Reusability: The above code is not reusable. If we want to re-use the code of a specific type of bird, we would have to change the above code.
  4. Parallel development - The code is not parallel development friendly. If multiple developers are working on the same code, they could face merge conflicts.

Before fixing the SRP violation, Let’s see the Open Closed Principle(OCP) since SRP and OCP are related to each other.

Open Closed Principle

The Open/Closed Principle states that a class should be open for extension but closed for modification. This means that we should be able to add new functionality to the class without changing the existing code.

In our Bird class if we wanted to add a new type of Bird, then we ended up modifying the fly method because the type is tightly coupled with the fly method, this is a violation of OCP.

This principle aims to extend a Class’s behavior without changing the existing behavior of that Class. This is to avoid causing bugs wherever the Class is being used.

How to Fix SRP and OCP

  1. We aim to eliminate the decision-making responsibility within the Bird class regarding which fly method to call.
  2. We have to find a way to add a new type of bird without modifying the fly method.

Solution

  1. Create an abstract class with all common and abstract fields
abstract class Bird{
private int weight;
private String colour;
private String type;
private String size;
private String beakType;

public abstract void fly();

public void eat() {
System.out.println("Eating");
}

public void makeSound() {
System.out.println("make sound");
}
}

2. Create child classes for each bird type

public class Eagle extends Bird{
public void fly()
{
System.out.println("Eagle is flying");
}
}

public class Parrot extends Bird{
public void fly()
{
System.out.println("Parrot is flying");
}
}

public class Penguin extends Bird{
public void fly()
{
System.out.println("Penguin is flying");
}
}
  1. Since we removed decision-making responsibility within the Bird class SRP violation is fixed
  2. If we want to add a new type, we don’t need to modify the fly method anymore. We just have to create a new class inherited from the Bird class and Implement the fly method

The client code looks

main()
{
// Creating eagle instance
Bird eagle = new Eagle();
eagle.fly();

// Creating Parrot instance
Bird eagle = new Parrot();
eagle.fly();
}

Summary

So far, we have discussed three principles and highlighted their goals. In the upcoming article, we’ll delve into the remaining three principles.

Thank you so much for reading. I hope you have a better idea about this topic and you had as much fun reading this as I did writing it.

If you have any questions or suggestions, leave a comment

--

--

Ramkumar

Passionate tech blogger diving into programming and emerging tech. Join me for insights and updates on the evolving world of software development!