Patrón Singleton
Parte de la sección Programación orientada a objetos del Journey de GDScript de Coddy. Lección 46 de 65.
El patrón Singleton garantiza que una clase tenga exactamente un objeto y ofrece a todos los scripts una forma de acceder a él. Úsalo para cosas de las que un juego solo tiene una: la configuración, el sistema de guardado y el gestor de puntuación.
En GDScript, una static var contiene el objeto único, y una static func lo crea la primera vez que alguien lo solicita:
# 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 pertenece a la clase, no a un objeto, así que todos los scripts ven la misma variable. La primera llamada la encuentra vacía y crea el objeto; todas las llamadas posteriores devuelven ese mismo objeto.
# 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 y b son dos variables que contienen un mismo objeto, así que el cambio realizado mediante a también se refleja en b. Para los objetos, == es true solo cuando ambos lados son el mismo objeto.
GDScript no puede hacer que _init() sea privado, así que nada impide que un script llame a GameSettings.new() y obtenga un segundo objeto. El guion bajo en _instance y el método get_instance() son el acuerdo: los scripts solicitan el objeto, nunca lo crean.
En un proyecto de Godot, la forma habitual de obtener un objeto compartido es mediante un autoload: un script que registras en la configuración del proyecto, que Godot crea una vez al iniciar el juego y pone a disposición por nombre en todos los scripts. Es un Singleton que Godot administra por ti. Los autoloads se configuran en el editor, así que los desafíos de aquí construyen el patrón en código con static var.
Desafío
FácilCada moneda de un juego se suma a una única puntuación compartida. Convierte ScoreManager en un singleton:
- Un
static varguarda el único objeto. static func get_instance()lo devuelve y lo crea en la primera llamada. Justo después de crearlo, imprimeScore manager created.add_points(points)suma puntos ascore.
En coin.gd, collect() suma el value de la moneda a la puntuación mediante ScoreManager.get_instance().
El código proporcionado lee cuántos eventos vienen a continuación y luego lee un evento por línea: coin VALUE recoge una moneda nueva, bonus POINTS suma puntos directamente. Después de cada evento, imprime la puntuación y, al final, indica si dos llamadas a get_instance() devuelven el mismo objeto. Para coin 5 y bonus 20, la salida es:
Score manager created
Score: 5
Score: 25
Same object: trueTu código va en score_manager.gd y coin.gd. main.gd contiene el código de entrada/salida proporcionado y no se puede editar.
Pruébalo tú mismo
extends Node
func _ready():
# Código de entrada/salida proporcionado: mantenlo tal como está
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()))
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Programación orientada a objetos
1Fundamentos de la programación orientada a objetos
Archivos externosIntroducción a la programación orientada a objetosClases vs. objetosLa palabra clave selfMétodosPropiedadesConstructor (_init)Repaso: calculadora sencilla4Polimorfismo
Repaso de la sobrescritura de métodosTipado patoClases y métodos abstractosDiseño de interfacesRepaso: calculadora de formas7Señales
¿Qué es una señal?Declarar y emitirConectarse a las señalesSeñales con argumentosRepaso: sistema de salud10Patrones de diseño, parte 2
Patrón CommandPatrón AdapterPatrón DecoratorPatrón Template MethodPatrón StatePatrón Composite2Propiedades de clase
Variables de instancia y estáticasFunciones estáticasMétodos setter de propiedadesMétodos getter de propiedadesPrivado por convenciónRepaso: administrador de cuentas bancarias5Encapsulación
Miembros públicos y privadosValidación con settersOcultación de informaciónPropiedades de solo lecturaRepaso: sistema de registros de estudiantes8Conceptos avanzados de POO
Composición frente a herenciaClases internasNodos como componentesRefCounted frente a NodeEnums en clases3Herencia
Herencia básicaLa palabra clave superSobrescritura de métodosCadenas de herenciaComprobaciones de tipo con isRepaso: jerarquía de empleados6Métodos especiales
Introducción a los métodos virtualesEl método _to_stringIteradores personalizadosRepaso: lista personalizada9Patrones de diseño, parte 1
Introducción a los patrones de diseñoPatrón SingletonPatrón FactoryPatrón ObserverPatrón StrategyPractica por tu cuenta: Compilador de GDScript online