Menu
CoddyTech

模板方法模式

本课属于 Coddy GDScript 学习旅程的“面向对象编程”单元。第 53 课,共 65 课。

模板方法模式会在父类中固定算法各步骤的顺序,并让每个子类补充其中一些步骤。负责运行这些步骤的父类方法就是模板方法。

# level.gd
@abstract
class_name Level
extends RefCounted

func play() -> void:
	print("Loading ", get_level_name())
	spawn_enemies()
	print("Level complete!")

@abstract func get_level_name() -> String
@abstract func spawn_enemies() -> void

play() 是模板:每个关卡都会按此顺序加载、生成敌人并完成。不同的步骤是抽象的,因此每个子类都必须编写这些步骤:

# forest_level.gd
class_name ForestLevel
extends Level

func get_level_name() -> String:
	return "Forest"

func spawn_enemies() -> void:
	print("3 wolves appear")

CaveLevel 的写法相同,名称是 "Cave",并且会出现 5 bats appear。

# main.gd
var levels: Array[Level] = [ForestLevel.new(), CaveLevel.new()]
for level in levels:
	level.play()
Loading Forest
3 wolves appear
Level complete!
Loading Cave
5 bats appear
Level complete!

父类中的步骤也可以有默认实现,子类可以重写它。这样的可选步骤称为钩子:

# level.gd
func play() -> void:
	print("Loading ", get_level_name())
	spawn_enemies()
	if has_boss():
		print("The boss arrives")
	print("Level complete!")

func has_boss() -> bool:
	return false

只有重写 has_boss() 并让它返回 true 的关卡才会显示首领台词。子类编写步骤,父类决定这些步骤何时运行,所以子类不改动 play(),每个关卡都遵循相同的顺序。

challenge icon

挑战

中等

游戏会按相同的步骤以两种格式导出分数。每一行都是一个包含 "name" 和 "score" 的字典。

  • 在 exporter.gd 中,编写模板方法 export_rows(rows):它会打印 header(),然后为每一行打印 format_row(row),最后打印 footer(rows)。如果页眉或页脚是空字符串,就不打印。钩子 header() 和 footer() 默认返回 "",而 format_row() 是抽象的。
  • CsvExporter:页眉是 name,score,一行的内容是 Ada,12。没有页脚。
  • ListExporter:没有页眉,一行的内容是 * Ada scored 12,页脚是带有行数的 Players: N。

提供的代码会读取格式(csv 或 list)、后续行数,然后逐行读取 NAME SCORE。当格式为 list,且输入为 Ada 12 和 Bo 7 时,输出如下:

* Ada scored 12
* Bo scored 7
Players: 2

你的代码应写在 exporter.gd、csv_exporter.gd 和 list_exporter.gd 中。main.gd 包含提供的输入/输出代码,不能编辑。

亲手试试

extends Node

func _ready():
	# 已提供的输入和输出代码:保持原样。
	var style := OS.read_string_from_stdin()
	var rows: Array = []
	var count := int(OS.read_string_from_stdin())
	for i in count:
		var parts := OS.read_string_from_stdin().split(" ")
		rows.append({"name": parts[0], "score": int(parts[1])})
	var exporter: Exporter = CsvExporter.new()
	if style == "list":
		exporter = ListExporter.new()
	exporter.export_rows(rows)
quiz icon自我测试

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

面向对象编程中的所有课

自己练习: GDScript 在线编译器