Language: English O’zbek

Single Responsibility Principle (SRP)

A class should have only one reason to change.

Each class or module should encapsulate a single responsibility. When a class handles multiple concerns (e.g. business logic, persistence, formatting), a change in any one area forces the entire class to be modified and re-tested.

Diagram

SRP class diagram

Violation

In violation.py the Order class handles three unrelated responsibilities:

  • Price calculation — computing the order total
  • Discount logic — applying business discount rules
  • Persistence — saving the order to a database
class Order:
    def __init__(self, items: list[Item]) -> None:
        self.items = items
        self.total_price = self.calculate_total()
        self.total_price = self.apply_discount(self.total_price)
        self.save()

Any change to discount rules, pricing formulas, or storage backends forces modification of this single class.

Correct

In correct.py each responsibility is extracted into its own class:

Class Responsibility
Order Holds order data
PriceCalculator Computes the total price
DiscountApplier Applies discount rules
OrderRepository Handles persistence
@dataclass
class Order:
    items: list[Item] = field(default_factory=list)
    total_price: float = 0.0

    def finalize(self) -> None:
        self.total_price = PriceCalculator.total(self.items)
        self.total_price = DiscountApplier.apply(self.total_price)
        OrderRepository.save(self)

Now each class has exactly one reason to change, and they can be tested, extended, or replaced independently.