包括的なインターフェースがあるより、いくつかの特定のインターフェースに分割すべき。
Before
from abc import ABC, abstractmethod
class Order:
def __init__(self):
self.items = []
self.quantities = []
self.prices = []
self.status = 'open'
def add_item(self, name, quantity, price):
self.items.append(name)
self.quantities.append(quantity)
self.prices.append(price)
def total_price(self):
total = 0
for i in range(len(self.prices)):
total += self.quantities[i] * self.prices[i]
return total
class PaymentProcessor(ABC):
@abstractmethod
def auth_sms(self, code):
pass
@abstractmethod
def pay(self, order):
pass
class DebitPaymentProcessor(PaymentProcessor):
def __init__(self, security_code):
self.security_code = security_code
self.verified = False
def auth_sms(self, code):
print(f'Verifying SMS code {code}')
self.verified = True
def pay(self, order):
if not self.verified:
raise Exception('Not authorized')
print('Processing debit payment type')
print(f'Verifying security code: {self.security_code}')
order.status = 'paid'
class CreditPaymentProcessor(PaymentProcessor):
def __init__(self, security_code):
self.security_code = security_code
def auth_sms(self, code):
raise Exception('Credit card payments don't support SMS code authorization.')
def pay(self, order):
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
self.verified = False
def auth_sms(self, code):
print(f'Verifying SMS code {code}')
self.verified = True
def pay(self, order):
if not self.verified:
raise Exception('Not authorized')
print('Processing paypal payment type')
print(f'Using 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 = DebitPaymentProcessor('2349875')
processor.auth_sms(465839)
processor.pay(order)
Before
from abc import ABC, abstractmethod
class Order:
def __init__(self):
self.items = []
self.quantities = []
self.prices = []
self.status = 'open'
def add_item(self, name, quantity, price):
self.items.append(name)
self.quantities.append(quantity)
self.prices.append(price)
def total_price(self):
total = 0
for i in range(len(self.prices)):
total += self.quantities[i] * self.prices[i]
return total
class PaymentProcessor(ABC):
@abstractmethod
def auth_sms(self, code):
pass
@abstractmethod
def pay(self, order):
pass
class DebitPaymentProcessor(PaymentProcessor):
def __init__(self, security_code):
self.security_code = security_code
self.verified = False
def auth_sms(self, code):
print(f'Verifying SMS code {code}')
self.verified = True
def pay(self, order):
if not self.verified:
raise Exception('Not authorized')
print('Processing debit payment type')
print(f'Verifying security code: {self.security_code}')
order.status = 'paid'
class CreditPaymentProcessor(PaymentProcessor):
def __init__(self, security_code):
self.security_code = security_code
def auth_sms(self, code):
raise Exception('Credit card payments don't support SMS code authorization.')
def pay(self, order):
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
self.verified = False
def auth_sms(self, code):
print(f'Verifying SMS code {code}')
self.verified = True
def pay(self, order):
if not self.verified:
raise Exception('Not authorized')
print('Processing paypal payment type')
print(f'Using 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 = DebitPaymentProcessor('2349875')
processor.auth_sms(465839)
processor.pay(order)
上記の場合、auth_sms を汎用的な
PaymentProcessor に設定しているが、
CreditPaymentProcessor では本来必要ない。
そのため、PaymentProcessor の
サブクラス PaymentProcessor_SMS を作成し、PaymentProcessor を継承させる。
DebitPaymentProcessor, PaypalPaymentProcessor は auth_sms が必要なため、
PaymentProcessor_SMS を継承させる。
After
from abc import ABC, abstractmethod
class Order:
def __init__(self):
self.items = []
self.quantities = []
self.prices = []
self.status = 'open'
def add_item(self, name, quantity, price):
self.items.append(name)
self.quantities.append(quantity)
self.prices.append(price)
def total_price(self):
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):
pass
class PaymentProcessor_SMS(PaymentProcessor):
@abstractmethod
def auth_sms(self, code):
pass
class DebitPaymentProcessor(PaymentProcessor_SMS):
def __init__(self, security_code):
self.security_code = security_code
self.verified = False
def auth_sms(self, code):
print(f'Verifying SMS code {code}')
self.verified = True
def pay(self, order):
if not self.verified:
raise Exception('Not authorized')
print('Processing debit payment type')
print(f'Verifying security code: {self.security_code}')
order.status = 'paid'
class CreditPaymentProcessor(PaymentProcessor):
def __init__(self, security_code):
self.security_code = security_code
def pay(self, order):
print('Processing credit payment type')
print(f'Verifying security code: {self.security_code}')
order.status = 'paid'
class PaypalPaymentProcessor(PaymentProcessor_SMS):
def __init__(self, email_address):
self.email_address = email_address
self.verified = False
def auth_sms(self, code):
print(f'Verifying SMS code {code}')
self.verified = True
def pay(self, order):
if not self.verified:
raise Exception('Not authorized')
print('Processing paypal payment type')
print(f'Using 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 = DebitPaymentProcessor('2349875')
processor.auth_sms(465839)
processor.pay(order)
Composision
from abc import ABC, abstractmethod
class Order:
def __init__(self):
self.items = []
self.quantities = []
self.prices = []
self.status = 'open'
def add_item(self, name, quantity, price):
self.items.append(name)
self.quantities.append(quantity)
self.prices.append(price)
def total_price(self):
total = 0
for i in range(len(self.prices)):
total += self.quantities[i] * self.prices[i]
return total
class SMSAuth:
authorized = False
def verify_code(self, code):
print(f'Verifying code {code}')
self.authorized = True
def is_authorized(self) -> bool:
return self.authorized
class PaymentProcessor(ABC):
@abstractmethod
def pay(self, order):
pass
class DebitPaymentProcessor(PaymentProcessor):
def __init__(self, security_code, authorizer: SMSAuth):
self.authorizer = authorizer
self.security_code = security_code
def pay(self, order):
if not self.authorizer.is_authorized():
raise Exception('Not authorized')
print('Processing debit payment type')
print(f'Verifying security code: {self.security_code}')
order.status = 'paid'
class CreditPaymentProcessor(PaymentProcessor):
def __init__(self, security_code):
self.security_code = security_code
def pay(self, order):
print('Processing credit payment type')
print(f'Verifying security code: {self.security_code}')
order.status = 'paid'
class PaypalPaymentProcessor(PaymentProcessor):
def __init__(self, security_code, authorizer: SMSAuth):
self.authorizer = authorizer
self.email_address = email_address
def pay(self, order):
if not self.authorizer.is_authorized():
raise Exception('Not authorized')
print('Processing paypal payment type')
print(f'Using 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())
authorizer = SMSAuth()
processor = DebitPaymentProcessor('2349875', authorizer)
authorizer.verify_code(465839)
processor.pay(order)