Wzorzec stanu
Część sekcji Programowanie obiektowe ścieżki GDScript w Coddy. Lekcja 54 z 65.
Wzorzec State przypisuje obiektowi osobny obiekt stanu dla każdego trybu, w którym może się on znajdować. Obiekt przekazuje wykonywaną pracę aktualnemu stanowi, więc jego zachowanie zmienia się wraz ze zmianą stanu.
W przypadku kilku stanów wystarczą enum i instrukcja match. Gdy każdy stan reaguje na kilka działań na swój sposób, instrukcja match rozrasta się wraz z każdym stanem i każdym działaniem. Wzorzec State przenosi reguły każdego stanu do jego własnej klasy:
# hero_state.gd
@abstract
class_name HeroState
extends RefCounted
@abstract func get_state_name() -> String
@abstract func handle(action: String) -> HeroStatehandle() zwraca następny stan: nowy obiekt stanu, na który należy przejść, albo self, aby pozostać w bieżącym stanie.
# 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 jest zapisany w ten sam sposób: jego nazwa to "Running", a "stop" zwraca IdleState.new(). Bohater, czyli kontekst, przechowuje bieżący stan i pyta go, co ma zrobić:
# 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 -> IdleTo samo działanie oznacza różne rzeczy w różnych stanach: "stop" nic nie robi, gdy bohater jest bezczynny, a zatrzymuje go, gdy biegnie. Każda reguła znajduje się w klasie danego stanu, więc nowy stan, taki jak skakanie, oznacza jedną nową klasę.
Stany zwracają następny stan zamiast przechowywać bohatera. Stan, który przechowywałby bohatera, gdyby bohater przechowywał stan, tworzyłby cykl referencji, a żaden z tych obiektów nigdy nie zostałby zwolniony.
Wyzwanie
ŁatwyDrzwi są Locked, Closed lub Open. DoorState (door_state.gd) deklaruje get_state_name() i handle(action), a LockedState (locked_state.gd) jest już napisany: unlock zmienia stan drzwi na Closed. Napisz:
ClosedState.handle():openzwraca nowyOpenState,locknowyLockedState, a w pozostałych przypadkachself.OpenState.handle():closezwraca nowyClosedState, a w pozostałych przypadkachself.Door.handle_action(action): prosi bieżący stan o następny stan. Jeśli jest to ten sam obiekt, wypiszACTION: still STATE; w przeciwnym razie wypiszACTION: OLD -> NEWi przejdź do nowego stanu.
Drzwi zaczynają w stanie Locked. Dostarczony kod odczytuje liczbę kolejnych akcji, a następnie po jednej akcji w każdym wierszu, i wypisuje stan końcowy. Dla open, unlock, open, lock wynik to:
open: still Locked
unlock: Locked -> Closed
open: Closed -> Open
lock: still Open
Final state: OpenTwój kod umieść w plikach door.gd, closed_state.gd i open_state.gd. main.gd zawiera dostarczony kod wejścia/wyjścia i nie można go edytować.
Spróbuj swoich sił
extends Node
func _ready():
# Dostarczony kod wejścia/wyjścia: pozostaw go bez zmian
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())
Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.
Wszystkie lekcje w sekcji Programowanie obiektowe
1Podstawy programowania obiektowego
Pliki zewnętrzneWprowadzenie do programowania obiektowegoKlasy a obiektySłowo kluczowe selfMetodyWłaściwościKonstruktor (_init)Powtórka – prosty kalkulator4Polimorfizm
Ponowne omówienie przesłaniania metodDuck typingKlasy i metody abstrakcyjneProjektowanie interfejsówPowtórzenie – kalkulator kształtów7Sygnały
Czym jest sygnał?Deklarowanie i emitowanieŁączenie z sygnałamiSygnały z argumentamiPodsumowanie — system zdrowia10Wzorce projektowe, część 2
Wzorzec poleceniaWzorzec adapteraWzorzec dekoratoraWzorzec metody szablonowejWzorzec stanuWzorzec kompozytu2Właściwości klas
Zmienne instancji a zmienne statyczneFunkcje statyczneSettery właściwościGettery właściwościPrywatne z konwencjiPodsumowanie — menedżer kont bankowych5Enkapsulacja
Elementy publiczne i prywatneWalidacja za pomocą setterówUkrywanie informacjiWłaściwości tylko do odczytuPodsumowanie – system ewidencji uczniów8Zaawansowane koncepcje OOP
Kompozycja a dziedziczenieKlasy wewnętrzneWęzły jako komponentyRefCounted a NodeTypy wyliczeniowe w klasach11Projekt: Zarządzanie biblioteką
Przegląd projektuKlasy książki i użytkownika3Dziedziczenie
Podstawy dziedziczeniaSłowo kluczowe superNadpisywanie metodŁańcuchy dziedziczeniaSprawdzanie typów za pomocą isPodsumowanie – hierarchia pracowników6Metody specjalne
Wprowadzenie do metod wirtualnychMetoda _to_stringWłasne iteratoryPodsumowanie — własna lista9Wzorce projektowe — część 1
Wprowadzenie do wzorców projektowychWzorzec SingletonWzorzec FactoryWzorzec ObserverWzorzec StrategyPoćwicz samodzielnie: Kompilator GDScript online