Language: English O’zbek

Dependency Inversion Principle (DIP)

High-level modules should not depend on low-level modules. Both should depend on abstractions.

Instead of hard-wiring concrete classes, use dependency injection to pass abstractions. This decouples components and makes the system easier to test and extend.

Diagram

DIP class diagram

Violation

In violation.py PaymentProcessor directly creates a CreditCardPayment inside its constructor:

class PaymentProcessor:
    def __init__(self) -> None:
        self.payment = CreditCardPayment()  # hard-wired dependency

    def process(self, amount: float) -> None:
        self.payment.pay(amount)

Switching to cash or cryptocurrency requires modifying the processor itself.

Correct

In correct.py both the processor and payment methods depend on a Payment abstraction:

class Payment(ABC):
    @abstractmethod
    def pay(self, amount: float) -> None: ...

class PaymentProcessor:
    def __init__(self, payment: Payment) -> None:
        self.payment = payment

    def process(self, amount: float) -> None:
        self.payment.pay(amount)

New payment methods are added by implementing Paymentthe processor never changes:

for method in (CashPayment(), CreditCardPayment(), CryptoPayment()):
    processor = PaymentProcessor(method)
    processor.process(150.00)