Patron État
Fait partie de la section Programmation orientée objet du Journey R de Coddy. Leçon 48 sur 57.
Un objet utilisant le modèle state se comporte différemment selon son état actuel. Chaque état est une liste de fonctions gestionnaires, et l’objet transmet chaque requête aux gestionnaires de l’état dans lequel il se trouve :
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
}Sortie :
green : go
yellow : slow down
red : stop
green : go Les gestionnaires prennent un événement et renvoient l’état suivant ainsi qu’une réponse, de sorte que les transitions sont des données plutôt qu’une chaîne de if. Un tourniquet se déverrouille lorsqu’une pièce est insérée et se verrouille à nouveau après le passage de quelqu’un :
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")
}Sortie :
push -> blocked
coin -> unlocked
coin -> already open
push -> welcome La machine elle-même est une petite fermeture : elle conserve l’état actuel, recherche le gestionnaire et renvoie ignored pour un événement que l’état ne connaît pas :
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")Sortie :
press : light on | on
kick : ignored | on
press : light off | off Un nouvel état est une nouvelle entrée dans la liste. La machine ne change pas, et seuls les états qui mènent au nouveau ont besoin d’un nouveau gestionnaire :
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")
}Sortie :
press : on
overheat : fuse blown
press : ignored
repair : repaired Défi
FacileComplétez le tourniquet dans Turnstile.R. La liste states contient les états locked et unlocked, et chaque gestionnaire renvoie list(to = ..., say = ...) :
- locked :
coindéverrouille avecunlocked;pushreste verrouillé avecblocked; - unlocked :
coinreste déverrouillé avecthanks, already open;pushverrouille avecwelcomeet compte un passage.
Complétez ensuite make_turnstile(), qui démarre dans l'état locked et renvoie handle(event) (la réponse, ou ignored pour un événement inconnu), state() et passes(). Comptez un passage chaque fois que push est traité dans l'état unlocked. Le code fourni lit les événements et affiche chaque réponse avec le nouvel état, puis le nombre de passages.
Votre code doit se trouver dans Turnstile.R. main.R contient le code fourni d'entrée/sortie et ne peut pas être modifié.
Essayez vous-même
source("Turnstile.R")
# Code d'entrée/sortie fourni : le garder tel quel
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 = "")
Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.
Toutes les leçons de Programmation orientée objet
1Bases de S3
Travailler avec les fichiersListes avec une classeFonctions constructricesMéthodes print et formatValidateurs et fonctions utilitairesRécapitulatif - Températures4Encapsulation dans R
Les fermetures comme objetsLes environnements comme objetsFonctions d’accèsProtéger l’étatRécapitulatif - Parcmètre2S3 : génériques et méthodes
Génériques et UseMethodMéthodes par défautMéthodes pour les génériques de baseNotions de base sur NextMethodRécapitulatif - Aires des formes5Classes S4
Définir des classes S4Slots et accèsVérifications de validitéMéthodes showRécapitulatif - Catalogue de produits8Classes de référence
Définition des classes de référenceMéthodes et mises à jour des champsSémantique de copieHéritage et callSuperRécapitulatif - File d’attente des tâches11Projet : gestion de bibliothèque
Livres et membresEmprunter des livres3Héritage S3
Vecteurs de classesOrdre de recherche des méthodesÉtendre avec NextMethodVérifier avec inherits()Récapitulatif - Paie du personnelEntraînez-vous par vous-même : Compilateur R en ligne