工厂模式
本课属于 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 bossEnemyFactory.create_boss("orc", 3) 会返回一个拥有 300 HP 的 Orc。
挑战
中等生成表会列出敌人和等级。Enemy(enemy.gd)及其子类 Goblin(goblin.gd)已经写好,请完成其余部分:
- 在
orc.gd中,构造函数_init(level)将名称Orc、25 * levelHP 和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)
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: GDScript 在线编译器