DEV Community

Yaswanth K N
Yaswanth K N

Posted on

SOLID Principles

  • These are five principles of object oriented programming, helps in writing clean code and build good architecture.
  • These are first introduced by Robert J. Martin (a.k.a Uncle Bob).
  • SOLID stands for :
    • Single Responsibility Principle
    • The Open-Closed Principle
    • The Liskov Substitution Principle
    • Interface Segregation Principle
    • The Dependency Inversion Principle

Single Responsibility Principle

  • Simple definition is that a Class should be responsible for only one function
class Invoice:

    def calculate(self):
        # calculates total amount
    def print_invoice(self):
        # Prints invoice in given format 
    def save_invoice(self):
        # Saves to file
Enter fullscreen mode Exit fullscreen mode

Explanation:

  • In the above example, let's say Invoice class will calculate and prints the invoice slip
  • So, here SRP is voilating.
  • Because, SRP states that there should be only one reason to change or modify a class
  • But in the above example, If you want to change the format of invoice printing you will have to change invoice class.
  • If you want to change some business logic in calculate method again you have to change the invoice class
  • So, here same class is responsible for two things Soluton:
class InvoiceCalculate:
    def calculate(self):
        # calculates total amount

class PrintInvoice:
    def print_invoice(self):
        # Prints invoice in given format 
class SaveInvoice:
    def save_invoice(self):
        # Saves to file
Enter fullscreen mode Exit fullscreen mode
  • Here we are transporting three methods to three different class, as they have different functionalities

The Open-Closed Principle

  • This principle states that class should be closed for modification and open for extension
  • Meaning, If you want to add fuctionality to the class you don't want to change the existing code as this will arise bugs
  • Let's say if you want to save the invoice to both database and file
  • You can do as follows Example:
class SaveInvoice:
    def save_invoice(self):
        # Saves to file
    def save_invoice_database(self):
        # Saves to database
Enter fullscreen mode Exit fullscreen mode
  • In the above code Open-Closed principle has been violated
  • Because, we are changing or modifying the existing class for adding a new functionality
  • So, to solve the above problem we can use abstraction Solution:
  • we will create SaveInvoice as a abstract class instead of concrete class and we will inherit the class to impliment the required function
from abc import ABC,abstractmethod
# Base class
class SaveInvoice(ABC):
    @abstractmethod
    def save(self):
        pass

# class to imliment save function to save invoice to file
class SaveToFile(SaveInvoice):
    def save(self):
        # Save to file

# class to impliment save function to save invoice to database
class SaveToDatabase(SaveInvoice):
    def save(self):
        # Save to database
Enter fullscreen mode Exit fullscreen mode
  • In the above example we have used abstraction to overcome the problem of modifying the existing class
  • Even in future if we want to save invice to someother source we can always create a class corresponding to that and impliment save method from base class

The Liskov Substitution Principle

  • This principle states that Subclasses should be substitutable for their base classes
  • In other words, person who is using our code should not know which object he is implimenting or using

example:

  • This is closly related to the open closed priciple
from abc import ABC,abstractmethod
class polygone(ABC):
    def area(self):
        pass
class rectangle(polygone):
    def __init__(self,a,b):
        self.a = a
        self.b = b
    def area(self):
        return self.a*self.b
class square(polygone):
    def __init__(self,l):
        self.l = l
    def area(self):
        return self.l * self.l
rect = rectangle(a,b)
print(rect.area())
print(isinstance(rect,polygone))
Enter fullscreen mode Exit fullscreen mode
  • The above example is similar to open-close principle
  • Here, we can replace rect object with parent object polygone
  • So, Lisko Substitution principle is followed

Interface Segregation Principle

  • The Interface Segregation Principle is about separating the interfaces.
  • Keep multiple interfaces for multiple use cases
from abc import ABC,abstractmethod
class sim(ABC):
    def call(self):
        pass
    def message(self):
        pass
    def network(self):
        pass
Enter fullscreen mode Exit fullscreen mode
  • In the above example although the functionalities of these methods are different they are in same abstract class.
  • This will create obligation to impliment all the methods even though you want only call method

Solution

from abc import ABC,abstractmethod
class sim_call(ABC):
    @abstractmethod
    def call(self):
        pass
class sim_message(ABC):
    @abstractmethod
    def message(self):
        pass
class sim_network(ABC):
    @abstractmethod
    def network(self):
        pass

Enter fullscreen mode Exit fullscreen mode
  • Here, we have used three seperate abstract classes for all these different functions

The Dependency Inversion Principle

  • The Dependency Inversion principle states that our classes should depend upon interfaces or abstract classes instead of concrete classes and functions.
  • This is related to the open-close principle
  • we can use the same example as in Open-close principle
  • If we observe the given example, we have removed the SaveInvoice class which is concrete class and replaced them with abstract class to achieve DI principle

References

Top comments (0)