1. Single Responsibility Principle (SRP)
Concept: A class should have only one reason to change, meaning it should have only one responsibility or function.
Real-life Example: Think of a chef in a restaurant. Their primary responsibility is to cook delicious dishes. If the chef also starts serving customers, cleaning tables, and managing inventory, it becomes challenging to maintain the quality of the food. Similarly, in coding, a class that does too many things becomes hard to maintain.
class Cook:
def prepare_dish(self, dish):
# Cooking logic here
pass
class Waiter:
def serve_customer(self, customer, dish):
# Serving logic here
pass
class InventoryManager:
def track_inventory(self, item):
# Inventory tracking logic here
pass
In this example, each class has a single responsibility, making the code more maintainable.
2. Open-Closed Principle (OCP)
Concept: Software entities (classes, modules, functions) should be open for extension but closed for modification. In other words, you can add new functionality without changing existing code.
Real-life Example: Consider a car manufacturer designing a new car model. They can add new features like GPS, a sunroof, or better fuel efficiency without altering the fundamental structure of the car. This allows for easier upgrades and maintenance.
class Car:
def start_engine(self):
# Engine starting logic
pass
class UpgradedCar(Car):
def activate_gps(self):
# GPS activation logic
pass
By creating an UpgradedCar
class that inherits from Car
, we extend functionality without modifying the original Car
class.
3. Liskov Substitution Principle (LSP)
Concept: Subtypes must be substitutable for their base types without altering the correctness of the program. In simpler terms, if a class is a subclass, it should be able to replace its parent class without causing errors.
Real-life Example: Think of a remote control for various electronic devices. You should be able to use the same remote control for different TVs or DVD players without any issues, as long as they adhere to the basic remote control functions.
class RemoteControl:
def power_on(self):
pass
class TV(RemoteControl):
def power_on(self):
# TV-specific logic
pass
class DVDPlayer(RemoteControl):
def power_on(self):
# DVD player-specific logic
pass
Here, both TV
and DVDPlayer
are substitutable for the RemoteControl
base class.
4. Interface Segregation Principle (ISP)
Concept: Clients should not be forced to depend on interfaces they do not use. In other words, classes should have specific interfaces tailored to their needs, rather than a generic one-size-fits-all interface.
Real-life Example: Consider a smartphone. Users can interact with various apps like calling, texting, or browsing the internet. Imagine if every app had to include all possible features, making the phone overly complex. Instead, each app provides a specific set of features relevant to its purpose.
from abc import ABC, abstractmethod
class Email(ABC):
@abstractmethod
def send_email(self, to, subject, body):
pass
class SMS(ABC):
@abstractmethod
def send_sms(self, to, message):
pass
class NotificationService(Email, SMS):
def send_email(self, to, subject, body):
# Email sending logic
pass
def send_sms(self, to, message):
# SMS sending logic
pass
Here, Email
and SMS
interfaces define specific methods, and the NotificationService
class implements both interfaces. This adheres to ISP.
5. Dependency Inversion Principle (DIP)
Concept: High-level modules should not depend on low-level modules. Both should depend on abstractions. Abstractions should not depend on details; details should depend on abstractions.
Real-life Example: Think of a power socket. Appliances don’t depend on the socket type; they plug into an abstract socket interface. You can switch out sockets without affecting the appliances. In software, this means depending on abstract classes or interfaces rather than concrete implementations.
from abc import ABC, abstractmethod
class Switchable(ABC):
@abstractmethod
def turn_on(self):
pass
@abstractmethod
def turn_off(self):
pass
class LightBulb(Switchable):
def turn_on(self):
# Light bulb specific logic
pass
def turn_off(self):
# Light bulb specific logic
pass
class Fan(Switchable):
def turn_on(self):
# Fan specific logic
pass
def turn_off(self):
# Fan specific logic
pass
Here, both LightBulb
and Fan
depend on the Switchable
interface, adhering to DIP.
Incorporating the SOLID principles into your software development practices will lead to more maintainable, scalable, and robust code. Whether you’re building a simple Python script or a complex software system, these principles can help you navigate the intricate world of software development with confidence.