The SOLID principles are the five important principles of Object Oriented class design.Put simply, they are set of rules that every developer should follow while designing class structures.The main purpose of SOLID principles is to create understandable,readable and testable code that many developers can collaboratively work on.
The five SOLID principles are:
- Single Responsibility principle
- Open-Closed principle
- Liskov Substitution principle
- Interface Segregation principle
- Dependency Inversion principle
Let's look at these principles one by one with Python codes.
Single Responsibility Principle
The Single Responsibility principle states that every class, module and function in a program should have one single responsibility/purpose in that program and therefore should have only one reason to change.
Let's look at a code :
class Employeee:
def send_email(self):
pass
def employee_performance(self):
pass
The above code violates the Single responsibility principle as the employee class performs two responsibilities, sending email and assessing employee's performance.
Let's fix this code so that it follows SRP.
class EmployeeEmail:
def send_email(self):
pass
class Employeeperformace:
def employee_performance(self):
pass
Open Closed Principle
The Open Closed Principle states that the classes should be open for extension but closed for modification. This means that the class should be made in such a way that their core functionality can be extended to other classes without altering the initial class's source code.
class PersonStorage:
def savetodatabase(self, person):
print('saved the {} to database'.format(person))
def savetojson(self, person):
print('saved to {} json '.format(person))
if __name__ == '__main__':
p1 = 'Sam'
storage = PersonStorage()
storage.savetodatabase(p1)
In the above code suppose we want to save the person to XML file. It's not possible without modifying the class PersonStorage. So the above class is open to modification but closed to extension. Hence it does not follow OCP.
from abc import ABC, abstractmethod
class PersonStorage(ABC):
@abstractmethod
def save(self, person):
pass
class PersonDB(PersonStorage):
def save(self, person):
print(f'Save the {} to database'.format(person))
class PersonJSON(PersonStorage):
def save(self, person):
print(f'Save the {} to a JSON file'.format(person))
class PersonXML(PersonStorage):
def save(self, person):
print(f'Save the {} to a XML file'.format(person))
To solve the problem, we first created an abstract class PersonStorage and create an abstract method save in it.
After that we create a class for each saving type which inherits the abstract class PersonStorage. After that we override the save function everytime we create a new class.
Now our code follows OCP.
Liskov Substitution Principle
Liskov principle states that the object of a class should be able to be substituted by the object of it's subclass without
changing the code's correctness. This means that when an instance of a class is passed to another class, the child class must have a use case for all the properties and behaviour of the parent class .Let's look at some codes to understand this.
class Notification(ABC):
@abstractmethod
def notify(self, message, email):
pass
class Email(Notification):
def notify(self, message, email):
print(f'Send {message} to {email}')
class SMS(Notification):
def notify(self, message, phone):
print(f'Send {message} to {phone}')
The above example violates Liskovs Substitution principle as the as the notify method in SMS class takes phone as input instead of email.
from abc import ABC, abstractmethod
class Notification(ABC):
@abstractmethod
def notify(self, message):
pass
class Email(Notification):
def __init__(self, email):
self.email = email
def notify(self, message):
print(f'Send "{message}" to {self.email}')
class SMS(Notification):
def __init__(self, phone):
self.phone = phone
def notify(self, message):
print(f'Send "{message}" to {self.phone}')
To conform to the Liskov principle first we removed email as an argument from Notification abstract class. Then we made init method in both email and SMS class taking email and SMS respectively as the arguments.
Interface Segregation Principle
Interface Seggregation Principle states that the interface of a program should be split in such a way that the user has access to only the methods of their needs and they don't have to deal with unnecessary or complex methods which are of no use to them.Let's understand it with the help of code.
from abc import ABC, abstractmethod
class Vehicle(ABC):
@abstractmethod
def go(self):
pass
@abstractmethod
def fly(self)
pass
class Car(Vehicle):
def go(self):
print('Going on road')
class Airplane(Vehicle):
def go(self):
print('Going on runway')
def fly(self):
print('Flying in air')
In the above example notice that the class car has no use of the fly method. Hence Interface Segregation Principle is violated.
from abc import ABC, abstractmethod
class Movable(ABC):
@abstractmethod
def go(self):
pass
class Flyable(Vehicle):
def fly(self):
pass
class Car(Movable):
def go(self):
print('Going on road')
class Airplane(Flyable):
def go(self):
print('Going on runway')
def fly(self):
print('Flying in air')
We conformed to ISP by splitting vehicle into two interface movable and flyable.
Dependency Inversion
The Dependency Inversion Principle states that the classes in our function should depend on abstract classes rather than concrete classes.Let's understand it with the help of code.
class shape:
def length(self):
pass
def width(self):
pass
def area(self):
pass
class rectangle(self):
def length(self):
pass
def width(self):
pass
def area(self):
pass
The above class rectangle violates dependency inversion principle as it depends on a concrete class.
from abc import ABC,abstractmethod
class shape:(ABC)
@abstractmethod
def length(self):
pass
@abstractmethod
def width(self):
pass
@abstractmethod
def area(self):
pass
class rectangle(self):
def length(self):
pass
def width(self):
pass
def area(self):
pass
To conform to DIP we simply make the shape class as abstract class and all of it's methods as abstract methods.
References
https://www.freecodecamp.org/news/solid-principles-explained-in-plain-english/
https://www.freecodecamp.org/news/solid-principles-single-responsibility-principle-explained/
https://www.pythontutorial.net/python-oop/python-dependency-inversion-principle/
https://www.pythontutorial.net/python-oop/python-interface-segregation-principle/
https://www.pythontutorial.net/python-oop/python-liskov-substitution-principle/
https://www.pythontutorial.net/python-oop/python-open-closed-principle/
Top comments (0)