SOLID Principles Of Programming
- SOLID is a set of five design principles that help us to write maintainable and flexible code.
- They are, SRP (Single Responsibility Principle)
- OCP (Open-Closed Principle)
- LSP (Liskov Substitution Principle)
- ISP (Interface Segregation Principle)
- DIP (Dependency Inversion Principle)
1. SRP (Single Responsibility Principle)
- A class should have only a single responsibility.
- Due to this, it should also have only a single reason to change.
An example of a class that violates SRP:
class User:
def __init__(self, name, email, password):
self.name = name
self.email = email
self.password = password
def login(self):
pass
- In the above example, the class User is responsible for both managing user data and implementing login.
- We can make it adhere to SRP by making separate classes for user data and login.
class UserData:
def __init__(self, name, email, password):
self.name = name
self.email = email
self.password = password
class UserManager:
def login(self, user_data):
pass
2. OCP (Open-Closed Principle)
- A class should be open for extension and closed for modification.
- That is, we should be able to add new functionality without modifying existing code.
An example of a class that violates OCP:
class Shape:
def __init__(self, shape_type, dimensions):
self.shape_type = shape_type
self.dimensions = dimensions
def area(self):
if self.shape_type == 'rectangle':
pass
elif self.shape_type == 'circle':
pass
- In the above example, we will have to modify the existing code if we need to add a new shape.
- We can make it adhere to OCP by making abstract classes and methods.
from abc import ABC, abstractmethod
class Shape(ABC):
def __init__(self, shape_type, dimensions):
self.dimensions = dimensions
@abstractmethod
def area(self):
pass
class Rectangle(Shape):
def area(self):
pass
class Circle(Shape):
def area(self):
pass
class Triangle(Shape):
def area(self):
pass
3. LSP (Liskov Substitution Principle)
- A child class should be able to substitute its parent class.
- That is, any code that works on the parent class should also work on the child class.
An example of a class that violates LSP:
class Animal:
def __init__(self, name):
self.name = name
def eat(self):
pass
class Bird(Animal):
def fly(self):
pass
class Ostrich(Bird):
def fly(self):
raise NotImplementedError
- In the above example, Ostrich is a child class of Bird class but it raises an error when the fly method is called.
- We can fix this method by making Ostrich a child class of Animal instead of Bird.
class Animal:
def __init__(self, name):
self.name = name
def eat(self):
pass
class Bird(Animal):
def fly(self):
pass
class Ostrich(Animal):
pass
4. ISP (Interface Segregation Principle)
- A client should not be forced to depend on methods it does not use.
- That is, we should keep our interfaces small and focus only on functionality that the client needs.
An example of a class that violates ISP:
class Document:
def __init__(self, text):
self.text = text
def print(self):
pass
def fax(self):
pass
def scan(self):
pass
- In the above example, if a client only needs to print the document, they will still be forced to use the fax and scan method.
- We can make it adhere to ISP by splitting the Document class into smaller, more focused classes.
class Printable:
def print(self):
pass
class Faxable:
def fax(self):
pass
class Scanable:
def scan(self):
pass
class Document:
def __init__(self, text):
self.text = text
class Printer(Document, Printable):
pass
class Fax(Document, Faxable):
pass
class Scanner(Document, Scanable):
pass
5. DIP (Dependency Inversion Principle)
- Higher-level modules should not depend upon lower-level modules.
- Instead both should depend on abstractions.
An example of a class that violates DIP:
class Database:
def insert(self, data):
pass
class User:
def __init__(self, name, database):
self.name = name
self.database = database
def save(self):
pass
- In the above example, the class user is dependent on the class Database.
- To make it adhere to DIP, we can create an abstraction for the Database.
from abc import ABC, abstractmethod
class DatabaseInterface(ABC):
@abstractmethod
def insert(self, data):
pass
class Database(DatabaseInterface):
def insert(self, data):
pass
class User:
def __init__(self, name, database):
self.name = name
self.database = database
def save(self):
pass
Top comments (0)