サブクラスは、スーパークラスと置換可能でなければならない。

Before

from abc import ABC, abstractmethod

class Order:

    def __init__(self) -> None:
        self.items = []
        self.quantities = []
        self.prices = []
        self.status = 'open'

    def add_item(self, name: str, quantity: int, price: int) -> None:
        self.items.append(name)
        self.quantities.append(quantity)
        self.prices.append(price)

    def total_price(self) -> int:
        total = 0
        for i in range(len(self.prices)):
            total += self.quantities[i] * self.prices[i]
        return total


class PaymentProcessor(ABC):
    
    @abstractmethod
    def pay(self, order: Order, security_code: str) -> None:
        pass

class DebitPaymentProcessor(PaymentProcessor):
    def pay(self, order: Order, security_code: str) -> None:
        print('Processing debit payment type')
        print(f'Verifying security code: {security_code}')
        order.status = 'paid'

class CreditPaymentProcessor(PaymentProcessor):
    def pay(self, order: Order, security_code: str) -> None:
        print('Processing credit payment type')
        print(f'Verifying security code: {security_code}')
        order.status = 'paid'

order = Order()
order.add_item('Keyboard', 1, 50)
order.add_item('SSD', 1, 150)
order.add_item('USB cable', 2, 5)

print(order.total_price())
processor = CreditPaymentProcessor()
processor.pay(order, '0372846')

PaymentProcessor に PaypalPaymentProcessor を追加したい。
ただし、PaypalPaymentProcessor は security_code の代わりに email_address を使いたい。

After

from abc import ABC, abstractmethod

class Order:

    def __init__(self) -> None:
        self.items = []
        self.quantities = []
        self.prices = []
        self.status = 'open'

    def add_item(self, name: str, quantity: int, price: int) -> None:
        self.items.append(name)
        self.quantities.append(quantity)
        self.prices.append(price)

    def total_price(self) -> int:
        total = 0
        for i in range(len(self.prices)):
            total += self.quantities[i] * self.prices[i]
        return total


class PaymentProcessor(ABC):
    
    @abstractmethod
    def pay(self, order: Order) -> None:
        pass

class DebitPaymentProcessor(PaymentProcessor):

    def __init__(self, security_code: str) -> None:
        self.security_code = security_code

    def pay(self, order: Order) -> None:
        print('Processing debit payment type')
        print(f'Verifying security code: {self.security_code}')
        order.status = 'paid'

class CreditPaymentProcessor(PaymentProcessor):
    
    def __init__(self, security_code: str) -> None:
        self.security_code = security_code
    
    def pay(self, order: Order) -> None:
        print('Processing credit payment type')
        print(f'Verifying security code: {self.security_code}')
        order.status = 'paid'

class PaypalPaymentProcessor(PaymentProcessor):
    
    def __init__(self, email_address):
        self.email_address = email_address

    def pay(self, order: Order) -> None:
        print('Processing debit payment type')
        print(f'Verifying email address: {self.email_address}')
        order.status = 'paid'


order = Order()
order.add_item('Keyboard', 1, 50)
order.add_item('SSD', 1, 150)
order.add_item('USB cable', 2, 5)

print(order.total_price())
processor = PaypalPaymentProcessor('test@test.com')
processor.pay(order)