Паттерн «Одиночка»
Часть раздела Объектно-ориентированное программирование путешествия по GDScript на Coddy. Урок 46 из 65.
Паттерн Singleton гарантирует, что у класса есть ровно один объект, и предоставляет каждому скрипту единый способ получить к нему доступ. Используй его для того, что в игре существует только в единственном экземпляре: настроек, системы сохранения, подсчёта очков.
В GDScript static var хранит единственный объект, а static func создаёт его, когда кто-то впервые запрашивает его:
# game_settings.gd
class_name GameSettings
extends RefCounted
static var _instance: GameSettings = null
var volume := 50
static func get_instance() -> GameSettings:
if _instance == null:
_instance = GameSettings.new()
print("Creating settings")
return _instance_instance принадлежит классу, а не объекту, поэтому все скрипты видят одну и ту же переменную. Первый вызов обнаруживает, что она пуста, и создаёт объект; каждый последующий вызов возвращает тот же объект.
# main.gd
var a := GameSettings.get_instance()
var b := GameSettings.get_instance()
a.volume = 80
print(b.volume)
print(a == b)Creating settings
80
truea и b — это две переменные, содержащие один объект, поэтому изменение, внесённое через a, видно и через b. Для объектов == равно true только тогда, когда обе стороны — один и тот же объект.
В GDScript нельзя сделать _init() приватным, поэтому ничто не мешает скрипту вызвать GameSettings.new() и получить второй объект. Подчёркивание в _instance и метод get_instance() — это договорённость: скрипты запрашивают объект, а не создают его.
В проекте Godot обычный способ получить один общий объект — это автозагрузка: скрипт, который вы регистрируете в настройках проекта. Godot создаёт его один раз при запуске игры и предоставляет по имени в каждом скрипте. Это одиночка, управляемая Godot. Автозагрузка настраивается в редакторе, поэтому в этих заданиях этот подход реализуется в коде с помощью static var.
Задание
ЛегкоКаждая монета в игре увеличивает общий счёт. Сделайте ScoreManager синглтоном:
static varхранит единственный объект.static func get_instance()возвращает его, создавая при первом вызове. Сразу после создания он выводитScore manager created.add_points(points)увеличиваетscore.
В coin.gd метод collect() добавляет value монеты к счёту через ScoreManager.get_instance().
Предоставленный код считывает количество следующих событий, затем по одному событию в каждой строке: coin VALUE собирает новую монету, bonus POINTS напрямую добавляет очки. После каждого события он выводит счёт, а в конце — возвращают ли два вызова get_instance() один и тот же объект. Для coin 5 и bonus 20 вывод будет таким:
Score manager created
Score: 5
Score: 25
Same object: trueВаш код нужно поместить в score_manager.gd и coin.gd. В main.gd находится предоставленный код ввода/вывода, его нельзя редактировать.
Попробуйте сами
extends Node
func _ready():
# Предоставленный код ввода-вывода: оставьте его без изменений
var count := int(OS.read_string_from_stdin())
for i in count:
var parts := OS.read_string_from_stdin().split(" ")
if parts[0] == "coin":
Coin.new(int(parts[1])).collect()
elif parts[0] == "bonus":
ScoreManager.get_instance().add_points(int(parts[1]))
print("Score: %d" % ScoreManager.get_instance().score)
print("Same object: %s" % (ScoreManager.get_instance() == ScoreManager.get_instance()))
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыВведение в ООПКлассы и объектыКлючевое слово selfМетодыСвойстваКонструктор (_init)Повторение: простой калькулятор4Полиморфизм
Переопределение методов: повторениеУтиная типизацияАбстрактные классы и методыПроектирование интерфейсовПовторение — калькулятор фигур7Сигналы
Что такое сигнал?Объявление и отправкаПодключение к сигналамСигналы с аргументамиПовторение — система здоровья10Паттерны проектирования. Часть 2
Паттерн «Команда»Паттерн «Адаптер»Паттерн «Декоратор»Паттерн «Шаблонный метод»Паттерн «Состояние»Паттерн «Компоновщик»2Свойства классов
Переменные экземпляра и классаСтатические функцииСеттеры свойствГеттеры свойствПриватность по соглашениюПовторение — менеджер банковского счёта5Инкапсуляция
Открытые и закрытые членыПроверка данных с помощью сеттеровСокрытие информацииСвойства только для чтенияПовторение — система учета студентов8Продвинутые концепции ООП
Композиция и наследованиеВнутренние классыУзлы как компонентыRefCounted и NodeПеречисления в классах11Проект: Управление библиотекой
Обзор проектаКлассы книг и пользователей3Наследование
Основы наследованияКлючевое слово superПереопределение методовЦепочки наследованияПроверка типов с помощью isПовторение — иерархия сотрудников6Специальные методы
Введение в виртуальные методыМетод _to_stringПользовательские итераторыПовторение: пользовательский список9Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн «Одиночка»Паттерн «Фабрика»Паттерн «Наблюдатель»Паттерн «Стратегия»Потренируйтесь самостоятельно: Онлайн-компилятор GDScript