Menu
CoddyTech

模板方法模式

本课属于 Coddy Python 学习旅程的“面向对象编程”单元。第 52 课,共 64 课。

模板方法模式在基类中定义算法的框架,让子类可以重写特定步骤,而不改变算法的结构。

下面是一个包含模板方法的基类:

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!

要点:模板方法模式在父类中定义通用的算法结构,同时允许子类自定义具体步骤。父类控制整体流程,而子类提供具体实现。这样既能确保结构一致,又能让各个步骤保持灵活。

challenge icon

挑战

中等

在 template.py 中实现模板方法模式。抽象 Report 类拥有模板方法 generate(),它总是按相同顺序运行相同的三个步骤:header()、body()、footer()。

  • header() 由每个报告共享,并输出 === Report ===。
  • body() 是抽象方法:每个子类输出自己的内容。
  • footer() 是一个带默认实现的钩子,=== End ===,子类可以重写它。

然后编写两个具体的报告类:

  • SalesReport(total) 将总额存储在 self._total 中,并在主体中输出 Total sales: {total}。
  • InventoryReport(items) 将列表存储在 self._items 中,在主体中为每个项目输出 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()
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: Python 在线编译器