Padrão State
Parte da seção Programação orientada a objetos do Journey de GDScript da Coddy. Lição 54 de 65.
O padrão State dá a um objeto um objeto de estado separado para cada modo em que pode estar. O objeto delega seu trabalho ao estado atual, então seu comportamento muda quando o estado muda.
Para poucos estados, um enum e um match são suficientes. Quando cada estado reage a várias ações à sua maneira, esse match cresce a cada estado e a cada ação. O padrão State move as regras de cada estado para sua própria classe:
# hero_state.gd
@abstract
class_name HeroState
extends RefCounted
@abstract func get_state_name() -> String
@abstract func handle(action: String) -> HeroStatehandle() retorna o próximo estado: um novo objeto de estado para o qual mudar, ou self para permanecer.
# idle_state.gd
class_name IdleState
extends HeroState
func get_state_name() -> String:
return "Idle"
func handle(action: String) -> HeroState:
if action == "run":
return RunState.new()
return selfRunState é escrito da mesma forma: seu nome é "Running", e "stop" retorna IdleState.new(). O herói, o contexto, mantém o estado atual e pergunta a ele o que fazer:
# hero.gd
class_name Hero
extends RefCounted
var state: HeroState = IdleState.new()
func handle_action(action: String) -> void:
var next := state.handle(action)
if next != state:
print(state.get_state_name(), " -> ", next.get_state_name())
state = next# main.gd
var hero := Hero.new()
for action in ["stop", "run", "run", "stop"]:
hero.handle_action(action)Idle -> Running
Running -> IdleA mesma ação significa coisas diferentes em estados diferentes: "stop" não faz nada enquanto está ocioso e para um herói em movimento. Cada regra fica na classe de seu estado, então um novo estado, como pular, é uma nova classe.
Os estados retornam o próximo estado em vez de armazenar o herói. Um estado que mantivesse o herói enquanto o herói mantém o estado criaria um ciclo de referências, e nenhum dos objetos seria liberado.
Desafio
FácilUma porta está Locked, Closed ou Open. DoorState (door_state.gd) declara get_state_name() e handle(action), e LockedState (locked_state.gd) já está implementado: unlock deixa a porta Closed. Escreva:
ClosedState.handle():openretorna um novoOpenState,lockretorna um novoLockedState, e qualquer outra coisa retornaself.OpenState.handle():closeretorna um novoClosedState, e qualquer outra coisa retornaself.Door.handle_action(action): solicita ao estado atual o próximo estado. Se for o mesmo objeto, imprimeACTION: still STATE; caso contrário, imprimeACTION: OLD -> NEWe muda para o novo estado.
A porta começa Locked. O código fornecido lê quantas ações vêm a seguir, depois uma ação por linha, e imprime o estado final. Para open, unlock, open, lock, a saída é:
open: still Locked
unlock: Locked -> Closed
open: Closed -> Open
lock: still Open
Final state: OpenSeu código deve ficar em door.gd, closed_state.gd e open_state.gd. main.gd contém o código fornecido de entrada/saída e não pode ser editado.
Experimente você mesmo
extends Node
func _ready():
# Código de entrada/saída fornecido: mantenha-o como está
var door := Door.new()
var count := int(OS.read_string_from_stdin())
for i in count:
door.handle_action(OS.read_string_from_stdin())
print("Final state: ", door.state.get_state_name())
Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Programação orientada a objetos
1Fundamentos da POO
Arquivos externosIntrodução à POOClasses vs. objetosA palavra-chave selfMétodosPropriedadesConstrutor (_init)Revisão - Calculadora simples4Polimorfismo
Revisitando a Sobrescrita de MétodosDuck TypingClasses e Métodos AbstratosDesign de InterfacesRevisão - Calculadora de Formas7Sinais
O que é um sinal?Declarando e emitindoConectando-se a sinaisSinais com argumentosRevisão - Sistema de saúde10Padrões de Projeto Parte 2
Padrão CommandPadrão AdapterPadrão DecoratorPadrão Template MethodPadrão StatePadrão Composite2Propriedades de Classe
Variáveis de Instância vs. EstáticasFunções EstáticasMétodos Setters de PropriedadeMétodos Getters de PropriedadePrivado por ConvençãoRecapitulando: Gerenciador de Conta Bancária5Encapsulamento
Membros públicos e privadosValidação com settersOcultação de informaçõesPropriedades somente para leituraRevisão - Sistema de registros de alunos8Conceitos Avançados de POO
Composição vs. HerançaClasses InternasNós como ComponentesRefCounted vs. NodeEnums em Classes3Herança
Herança básicaA palavra-chave superSobrescrita de métodosCadeias de herançaVerificações de tipo com isRevisão - Hierarquia de funcionários6Métodos especiais
Introdução aos métodos virtuaisO método _to_stringIteradores personalizadosRevisão - Lista personalizada9Padrões de Projeto Parte 1
Introdução aos Padrões de ProjetoPadrão SingletonPadrão FactoryPadrão ObserverPadrão StrategyPratique por conta própria: Compilador de GDScript online