Menu
CoddyTech

工厂模式

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

工厂模式将选择要创建哪个类的操作集中在一个地方。程序的其余部分向工厂请求“一个地精”,然后得到一个对象,而无需指定类 Goblin。

这些产品共享一个父类,因此使用它们的代码可以适用于其中任意一个:

# enemy.gd
class_name Enemy
extends RefCounted

var hp := 10

func attack() -> String:
	return "The enemy waits"
# goblin.gd
class_name Goblin
extends Enemy

func attack() -> String:
	return "The goblin stabs"
# orc.gd
class_name Orc
extends Enemy

func attack() -> String:
	return "The orc smashes"

工厂是一个带有 static func 的类,它可以将名称转换为对象。它的返回类型是父类,因此它可以返回任何类型的敌人;如果是不认识的名称,则返回 null:

# enemy_factory.gd
class_name EnemyFactory
extends RefCounted

static func create(kind: String) -> Enemy:
	match kind:
		"goblin":
			return Goblin.new()
		"orc":
			return Orc.new()
	return null
# main.gd
for kind in ["orc", "goblin", "slime"]:
	var enemy := EnemyFactory.create(kind)
	if enemy == null:
		print("Unknown enemy: ", kind)
	else:
		print(enemy.attack())
The orc smashes
The goblin stabs
Unknown enemy: slime

这类名称通常来自数据:生成表、关卡文件,或玩家输入的命令。工厂是唯一负责将这些名称映射到类的地方,因此添加一个 Dragon 只需要新建一个文件,并在 match 中添加一个分支。

工厂也可以在返回对象之前完成初始化,这样每个调用者拿到的敌人都可以直接使用:

static func create_boss(kind: String, level: int) -> Enemy:
	var boss := create(kind)
	if boss != null:
		boss.hp = 100 * level
	return boss

EnemyFactory.create_boss("orc", 3) 会返回一个拥有 300 HP 的 Orc。

challenge icon

挑战

中等

生成表会列出敌人和等级。Enemy(enemy.gd)及其子类 Goblin(goblin.gd)已经写好,请完成其余部分:

  • 在 orc.gd 中,构造函数 _init(level) 将名称 Orc、25 * level HP 和 4 + level 点伤害传给父类构造函数,方式与 Goblin 相同。
  • 在 enemy_factory.gd 中,static func create(kind, level) 根据敌人名称返回用对应等级创建的 Goblin 或 Orc,分别对应 goblin 和 orc。名称中的大小写字母不影响结果(ORC 也会被识别为兽人)。其他名称都返回 null。

提供的代码会读取后续要生成的敌人数,然后为每个敌人读取一行 KIND LEVEL,并打印每个敌人的信息;如果名称无效,则打印 Unknown enemy: KIND,最后打印已生成的敌人数。对于 goblin 2、Orc 3 和 slime 1,输出为:

Goblin: 20 HP, 4 damage
Orc: 75 HP, 7 damage
Unknown enemy: slime
Spawned: 2

请在 enemy_factory.gd 和 orc.gd 中编写代码。main.gd 中包含提供的输入/输出代码,不能编辑。

亲手试试

extends Node

func _ready():
	# 提供的输入/输出代码:保持原样
	var spawned := 0
	var count := int(OS.read_string_from_stdin())
	for i in count:
		var parts := OS.read_string_from_stdin().split(" ")
		var enemy := EnemyFactory.create(parts[0], int(parts[1]))
		if enemy == null:
			print("Unknown enemy: ", parts[0])
		else:
			spawned += 1
			print(enemy.describe())
	print("Spawned: ", spawned)
quiz icon自我测试

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

面向对象编程中的所有课

自己练习: GDScript 在线编译器