「第8章: ファサードパターン - POS システムで考えよう」の巻
The Phantom of the Opera is there, inside my mind.
(オペラ座の怪人がそこにいる、私の心の中に)
- Christine (クリスティーン: 「オペラ座の怪人」より)
この章では、ユーザーからシステムの複雑な詳細を隠すための別の方法を見ていきましょう。システムを構成している全ての動作機構 (サブシステム) は、外部からはただ1つのエンティティと映れば十分です。
全てのシステムはパッと見た目よりは大体において複雑です。例えば POS システム (Point Of Sales) を考えてみましょう。ほとんど全ての方は、レジのお客さんとしての側からしかこのシステムとの接点はないでしょう。しかし、単純なケースにおいてさえ、すべての処理業務は多岐に渡ります。全ての売り上げを記録し、該当商品の在庫情報を更新し、会員になっている顧客のポイント数の更新作業もあるかもしれません。またほとんどのシステムでは、ある特定の商品にだけ適用する販売促進操作も可能になっています。たとえば、2つ購入するとその内の安い方が無料になる、などです。
この業務処理 (transaction process) は多くのサブシステムから成り立っています; 顧客ポイントといったロイヤリティシステム (loyalty system)、在庫システム (stock system)、販売促進システム (specials or promotions system)、決済システム (payment system) 等々が1つの大きなシステムを形成しています。そしてこれらの機能をそれぞれ異なるクラスとして実装することになるでしょう。
このような業務処理自体の実装を想像するのはそれほど難しいことではありません:
import datetime
import random
class Invoice:
def __init__(self, customer):
self.timestamp = datetime.datetime.now()
self.number = self.generate_number()
self.lines = []
self.total = 0
self.tax = 0
self.customer = customer
def save(self):
pass
def send_to_printer(self):
pass
def add_line(self, invoice_line):
self.lines.append(invoice_line)
self.calculate()
def remove_line(self, line_item):
try:
self.lines.remove(line_item)
except ValueError as e:
print(f'請求データ内に該当する項目が存在しません。\n項目の削除に失敗しました: {line_item}')
def calculate(self):
self.total = sum(x.total * x.amount for x in self.lines)
self.tax = sum(x.total * x.tax_rate for x in self.lines)
def generate_number(self):
rand = random.randint(1, 1000)
return f'{self.timestamp} {rand}'
class InvoiceLine:
def __init__(self, line_item):
pass
def save(self):
pass
class Receipt:
def __init__(self, invoice, payment_type):
self.invoice = invoice
self.customer = invoice.customer
self.payment_type = payment_type
pass
def save(self):
pass
class Item:
def __init__(self):
pass
@classmethod
def fetch(cls, item_barcode):
pass
def save(self):
pass
class Customer:
def __init__(self):
pass
@classmethod
def fetch(cls, customer_code):
pass
def save(self):
pass
class LoyaltyAccount:
def __init__(self):
pass
@classmethod
def fetch(cls, customer):
pass
def calculate(self, invoice):
pass
def save(self):
pass
売り上げを処理する際は、これら全てのクラスの関連性を考慮しながら操作を進めることになります:
def complex_sales_processor(customer_code, item_dict_list, payment_type):
customer = Customer.fetch(customer_code)
invoice = Invoice(customer)
for item_dict in item_dict_list:
item = Item.fetch(item_dict['barcode'])
item.amount_in_stock -= item_dict['amount_purchased']
item.save()
invoice_line = InvoiceLine(item)
invoice.add_line(invoice_line)
invoice.calculate()
invoice.save()
loyalty_account = LoyaltyAccount.fetch(customer)
loyalty_account.calculate(invoice)
loyalty_account.save()
receipt = Receipt(invoice, payment_type)
receipt.save()
いかがでしょうか?1つの売り上げの処理をするだけでも、これだけ多くのクラスとの煩雑なやり取りが必要です。