📚 Solid Principles in Python
💡 Newskategorie: Programmierung
🔗 Quelle: dev.to
The SOLID Principles:
- The Single-Responsibility Principle (SRP)
- The Open-Closed Principle (OCP)
- The Liskov Substitution Principle (LSP)
- The Interface Segregation Principle (ISP)
- The Dependency inversion Principle (DIP)
The Single-Responsibility Principle (SRP)
- This principle state that the Class should have only one responsibility.
- Code That violates SRP is:
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def greet(self):
print(f"Hello, my name is {self.name} and I'm {self.age} years old.")
def celebrate_birthday(self):
self.age += 1
print(f"{self.name} is now {self.age} years old!")
- In the above code, the Person class have two responsibility one is to greet and another one is to celebrate a birthday to follow the SRP create a different class one which handles greeting and the other handles birthday celebration.
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def greet(self):
print(f"Hello, my name is {self.name} and I'm {self.age} years old.")
class BirthdayCelebrator:
def celebrate_birthday(self, person):
person.age += 1
print(f"{person.name} is now {person.age} years old!")
The Open-Closed Principle (OCP)
- This principle states that the class should be closed for modification but open for extension.
- Code that violates OCP is:
from abc import ABC, abstractmethod
class Shape(ABC):
@abstractmethod
def area(self):
pass
class Rectangle(Shape):
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
class Circle(Shape):
def __init__(self, radius):
self.radius = radius
def area(self):
return 3.14 * self.radius ** 2
class Triangle(Shape):
def __init__(self, base, height):
self.base = base
self.height = height
def area(self):
return 0.5 * self.base * self.height
class AreaCalculator:
def calculate_area(self, shape):
if isinstance(shape, Rectangle):
return shape.area()
elif isinstance(shape, Circle):
return shape.area()
elif isinstance(shape, Triangle):
return shape.area()
- In the above code if we try to create a new class such as a hexagon we need to modify the AreaCalculator class which will violate OCP.
- To correct the code we just need to change the method of AreaCalculator class so there will be no need to modify AreaCalculator class.
from abc import ABC, abstractmethod
class Shape(ABC):
@abstractmethod
def area(self):
pass
class Rectangle(Shape):
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
class Circle(Shape):
def __init__(self, radius):
self.radius = radius
def area(self):
return 3.14 * self.radius ** 2
class Triangle(Shape):
def __init__(self, base, height):
self.base = base
self.height = heigh.t
def area(self):
return 0.5 * self.base * self.height
class AreaCalculator:
def calculate_area(self, shape):
return shape.area()
Liskov’s Substitution Principle (LSP)
- This principle states that the object created using the child class can replace the object created using The parent class.
- Code that violates LSP is:
class Bird:
def fly(self):
print("The bird is flying")
class Penguin(Bird):
def fly(self):
raise Exception("I can't fly")
def make_bird_fly(bird):
bird.fly()
bird = Bird()
make_bird_fly(bird) # Output: The bird is flying
penguin = Penguin()
make_bird_fly(penguin) # Output: An exception is raised
- In the above code, the penguin will raise the error when we call the fly method. To correct it simply do method ovveridding.
class Bird:
def fly(self):
print("The bird is flying")
class Penguin(Bird):
def fly(self):
print("I can't fly")
def make_bird_fly(bird):
bird.fly()
bird = Bird()
make_bird_fly(bird) # Output: The bird is flying
penguin = Penguin()
make_bird_fly(penguin) # output: I can't fly
Interface Segregation Principle (ISP)
- This principle states that it is better to have many small, specific interfaces, rather than one large, general-purpose interface.
- Code that violates ISP is:
from abc import ABC, abstractmethod
class Animal(ABC):
@abstractmethod
def eat(self):
pass
@abstractmethod
def sleep(self):
pass
@abstractmethod
def move(self):
pass
class Dog(Animal):
def eat(self):
print("The dog is eating")
def sleep(self):
print("The dog is sleeping")
def move(self):
print("The dog is running")
- Above code violates the ISP as if we try to create a fish class using an animal class but it doesn't have ability to move so we need to create methods which are common in all animals such as eating, sleep, and reproduction.
- Code that adheres ISP is:
from abc import ABC, abstractmethod
class Animal(ABC):
@abstractmethod
def eat(self):
pass
@abstractmethod
def sleep(self):
pass
@abstractmethod
def reproduce(self):
pass
- above method is common in all animals hence it is the simplest interface for animals and another method will be added according to other animals in their class.
Dependency Inversion Principle (DIP)
- This principle state that Entities must depend on abstractions, not on concretions. It states that the high-level module must not depend on the low-level module, but they should depend on abstractions.
- Code that violates DIP is:
class Shape:
def area(self):
pass
class Rectangle(Shape):
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
class Circle(Shape):
def __init__(self, radius):
self.radius = radius
def area(self):
return 3.14 * self.radius ** 2
class Triangle(Shape):
def __init__(self, base, height):
self.base = base
self.height = heigh.t
def area(self):
return 0.5 * self.base * self.height
class AreaCalculator:
def calculate_area(self, shape):
return shape.area()
- Code that adheres DIP is:
from abc import ABC, abstractmethod
class Shape(ABC):
@abstractmethod
def area(self):
pass
class Rectangle(Shape):
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
class Circle(Shape):
def __init__(self, radius):
self.radius = radius
def area(self):
return 3.14 * self.radius ** 2
class Triangle(Shape):
def __init__(self, base, height):
self.base = base
self.height = heigh.t
def area(self):
return 0.5 * self.base * self.height
class AreaCalculator:
def calculate_area(self, shape):
return shape.area()
References
- Geek For Geeks. "SOLID Principle in Programming: Understand With Real Life Examples". Retrieved from https://www.geeksforgeeks.org/solid-principle-in-programming-understand-with-real-life-examples/
- Geek For Geeks. "OOD Principles | SOLID". Retrieved from https://www.geeksforgeeks.org/ood-principles-solid/