Wzorzec Stan
Część sekcji Programowanie obiektowe ścieżki R w Coddy. Lekcja 48 z 57.
Obiekt we wzorcu state zachowuje się inaczej w zależności od swojego bieżącego stanu. Każdy stan jest listą funkcji obsługi, a obiekt przekazuje każde żądanie funkcjom obsługi stanu, w którym się znajduje:
states <- list(
green = list(label = "go", next_state = "yellow"),
yellow = list(label = "slow down", next_state = "red"),
red = list(label = "stop", next_state = "green")
)
current <- "green"
for (i in 1:4) {
cat(current, ":", states[[current]]$label, "\n")
current <- states[[current]]$next_state
}Wynik:
green : go
yellow : slow down
red : stop
green : go Obsługiwacze przyjmują zdarzenie i zwracają następny stan oraz odpowiedź, więc przejścia są danymi, a nie łańcuchem instrukcji if. Bramka obrotowa odblokowuje się po wrzuceniu monety i ponownie blokuje, gdy ktoś przez nią przejdzie:
states <- list(
locked = list(
coin = function() list(to = "unlocked", say = "unlocked"),
push = function() list(to = "locked", say = "blocked")
),
unlocked = list(
coin = function() list(to = "unlocked", say = "already open"),
push = function() list(to = "locked", say = "welcome")
)
)
current <- "locked"
for (event in c("push", "coin", "coin", "push")) {
r <- states[[current]][[event]]()
current <- r$to
cat(event, "->", r$say, "\n")
}Wynik:
push -> blocked
coin -> unlocked
coin -> already open
push -> welcome Samo urządzenie jest małym domknięciem: przechowuje bieżący stan, wyszukuje procedurę obsługi i zwraca ignored dla zdarzenia, którego dany stan nie zna:
make_machine <- function(states, start) {
current <- start
list(
handle = function(event) {
h <- states[[current]][[event]]
if (is.null(h)) return("ignored")
r <- h()
current <<- r$to
r$say
},
state = function() current
)
}
states <- list(off = list(press = function() list(to = "on", say = "light on")),
on = list(press = function() list(to = "off", say = "light off")))
m <- make_machine(states, "off")
for (e in c("press", "kick", "press")) cat(e, ":", m$handle(e), "|", m$state(), "\n")Wynik:
press : light on | on
kick : ignored | on
press : light off | off Nowy stan to nowy wpis na liście. Maszyna się nie zmienia, a nowego programu obsługi potrzebują tylko stany prowadzące do nowego stanu:
states <- list(
off = list(press = function() list(to = "on", say = "on")),
on = list(press = function() list(to = "off", say = "off"),
overheat = function() list(to = "broken", say = "fuse blown")),
broken = list(repair = function() list(to = "off", say = "repaired"))
)
current <- "off"
for (e in c("press", "overheat", "press", "repair")) {
h <- states[[current]][[e]]
if (is.null(h)) { cat(e, ": ignored\n"); next }
r <- h()
current <- r$to
cat(e, ":", r$say, "\n")
}Wynik:
press : on
overheat : fuse blown
press : ignored
repair : repaired Wyzwanie
ŁatwyUzupełnij kołowrót w Turnstile.R. Lista states zawiera stany locked i unlocked, a każdy moduł obsługi zwraca list(to = ..., say = ...):
- locked:
coinodblokowuje kołowrót, ustawiając stanunlocked;pushpozostawia go zablokowanym i zwracablocked; - unlocked:
coinpozostawia kołowrót odblokowany i zwracathanks, already open;pushblokuje go, zwracawelcomei zlicza jedno przejście.
Następnie uzupełnij make_turnstile(), która rozpoczyna działanie w stanie zablokowanym i zwraca handle(event) (odpowiedź lub ignored w przypadku nieznanego zdarzenia), state() i passes(). Zliczaj przejście za każdym razem, gdy push zostanie obsłużone w stanie odblokowanym. Dostarczony kod odczytuje zdarzenia i wyświetla każdą odpowiedź wraz z nowym stanem, a następnie liczbę przejść.
Twój kod umieść w Turnstile.R. Plik main.R zawiera dostarczony kod wejścia/wyjścia i nie można go edytować.
Spróbuj swoich sił
source("Turnstile.R")
# Dostarczony kod wejścia/wyjścia: pozostaw go bez zmian
input <- suppressWarnings(readLines(file("stdin")))
t <- make_turnstile()
for (event in input) cat(event, ": ", t$handle(event), " [", t$state(), "]\n", sep = "")
cat("passes: ", t$passes(), "\n", sep = "")
Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.
Wszystkie lekcje w sekcji Programowanie obiektowe
1Podstawy S3
Praca z plikamiListy z klasąFunkcje konstruktoraMetody print i formatWalidatory i funkcje pomocniczePowtórzenie — temperatury4Enkapsulacja w R
Domknięcia jako obiektyŚrodowiska jako obiektyFunkcje dostępoweOchrona stanuPodsumowanie – parkometr2Generics i metody S3
Generics i UseMethodMetody domyślneMetody dla podstawowych genericsPodstawy NextMethodPowtórzenie — pola figur5Klasy S4
Definiowanie klas S4Sloty i dostępSprawdzanie poprawnościMetody wyświetlaniaPodsumowanie – katalog produktów8Klasy referencyjne
Definiowanie klas referencyjnychMetody i aktualizacja pólSemantyka kopiowaniaDziedziczenie i callSuperPodsumowanie – kolejka zadań11Projekt: Zarządzanie biblioteką
Książki i czytelnicyWypożyczanie książek3Dziedziczenie S3
Wektory klasKolejność wyszukiwania metodRozszerzanie za pomocą NextMethodSprawdzanie za pomocą inherits()Powtórzenie — lista płac pracownikówPoćwicz samodzielnie: Kompilator R online