テンプレートメソッドパターン
CoddyのPythonジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 52/64。
Template Methodパターンは、アルゴリズムの骨格を基底クラスで定義し、サブクラスがアルゴリズムの構造を変更せずに特定のステップをオーバーライドできるようにします。
こちらはテンプレートメソッドを持つ基底クラスです。
class DataProcessor:
def process(self):
"""アルゴリズムの構造を定義するテンプレートメソッド"""
self.read_data()
self.process_data()
self.save_data()
def read_data(self):
print("Reading data...")
def process_data(self):
raise NotImplementedError("Subclasses must implement this")
def save_data(self):
print("Saving data...")テンプレートメソッド process() はアルゴリズムの手順を定義し、process_data() はサブクラスが実装するために残されています。
抽象メソッドを実装する具象クラスを作成します:
class CSVProcessor(DataProcessor):
def process_data(self):
print("Processing CSV data")
class JSONProcessor(DataProcessor):
def process_data(self):
print("Processing JSON data")各具象クラスは、必須ステップの独自の実装を提供します。
テンプレートメソッドを使用します:
csv_processor = CSVProcessor()
csv_processor.process()
print() # 空行
json_processor = JSONProcessor()
json_processor.process()ゲームテンプレートを使った別の例を作成します。
class Game:
def play(self):
"""ゲームをプレイするためのテンプレートメソッド"""
self.start_game()
self.play_game()
self.end_game()
def start_game(self):
print("Game started!")
def play_game(self):
raise NotImplementedError("Define the game rules")
def end_game(self):
print("Game ended!")
class Chess(Game):
def play_game(self):
print("Playing chess - thinking strategically...")
class Soccer(Game):
def play_game(self):
print("Playing soccer - running and kicking...")
chess = Chess()
chess.play()出力:
Reading data...
Processing CSV data
Saving data...
Reading data...
Processing JSON data
Saving data...
Game started!
Playing chess - thinking strategically...
Game ended!重要なポイント:Template Method Pattern は、サブクラスが特定のステップをカスタマイズできるようにしながら、親クラスで共通のアルゴリズム構造を定義します。親クラスが全体の流れを制御し、サブクラスが具体的な実装を提供します。これにより、一貫した構造を維持しながら、個々のステップに柔軟性を持たせることができます。
チャレンジ
中級template.py に Template Method パターンを実装してください。抽象 Report クラスは テンプレートメソッド generate() を持ち、常に同じ3つのステップを同じ順序で実行します:header()、body()、footer()。
header()はすべてのレポートで共有され、=== Report ===を出力します。body()は抽象メソッドです。各サブクラスが独自の内容を出力します。footer()はデフォルト値=== End ===を持つフックで、サブクラスでオーバーライドできます。
次に、2つの具象レポートを作成してください。
SalesReport(total)は合計をself._totalに保存し、body でTotal sales: {total}を出力します。InventoryReport(items)はリストをself._itemsに保存し、body で各アイテムについてItem: {item}を出力し、フッターをオーバーライドして=== {count} items ===を出力します。
driver.py はロックされています。このファイルはレポートを作成し、それらに対して generate() を呼び出します。サブクラス間で異なるのはステップだけであり、ステップの順序は基底クラスに一度だけ定義されています。
自分で試してみよう
from template import SalesReport, InventoryReport
# テストケースハンドラー(変更しないでください)
test_case = input()
if test_case == "sales_test":
SalesReport(1500).generate()
elif test_case == "inventory_test":
InventoryReport(["Laptop", "Mouse"]).generate()
elif test_case == "both_test":
for report in [SalesReport(200), InventoryReport(["Pen"])]:
report.generate()
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
自分で練習してみよう: Pythonオンラインコンパイラ