Menu
CoddyTech

Паттерн «Фабрика»

Часть раздела Объектно-ориентированное программирование путешествия по GDScript на Coddy. Урок 47 из 65.

Паттерн Factory переносит выбор класса для создания в одно место. Остальная часть программы просит фабрику создать «гоблина» и получает объект, не называя класс 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) возвращает Orc с 300 HP.

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 для goblin и Orc для 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