תבנית State
חלק מהיחידה תכנות מונחה עצמים במסלול ה-R של Coddy. שיעור 48 מתוך 57.
אובייקט בתבנית המצב מתנהג באופן שונה בהתאם למצב הנוכחי שלו. כל מצב הוא רשימה של פונקציות מטפלות, והאובייקט מעביר כל בקשה למטפלות של המצב שבו הוא נמצא:
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
}פלט:
green : go
yellow : slow down
red : stop
green : go מטפלים מקבלים אירוע ומחזירים את המצב הבא ואת התגובה, כך שהמעברים הם נתונים ולא שרשרת של if. קרוסלה נפתחת כשמכניסים מטבע וננעלת שוב אחרי שמישהו עובר:
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")
}פלט:
push -> blocked
coin -> unlocked
coin -> already open
push -> welcome המכונה עצמה היא סגירה קטנה: היא מחזיקה את המצב הנוכחי, מחפשת את המטפל, ומשיבה ignored עבור אירוע שהמצב אינו מכיר:
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")פלט:
press : light on | on
kick : ignored | on
press : light off | off מצב חדש הוא ערך חדש ברשימה. המכונה אינה משתנה, ורק המצבים שמובילים למצב החדש זקוקים למטפל חדש:
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")
}פלט:
press : on
overheat : fuse blown
press : ignored
repair : repaired אתגר
קלהשלימו את הקרוסלה ב-Turnstile.R. הרשימה states מכילה את המצבים locked ו-unlocked, וכל מטפל מחזיר list(to = ..., say = ...):
- locked:
coinפותח אותה באמצעותunlocked;pushמשאיר אותה נעולה באמצעותblocked; - unlocked:
coinמשאיר אותה פתוחה באמצעותthanks, already open;pushנועל אותה באמצעותwelcomeוסופר מעבר אחד.
לאחר מכן השלימו את make_turnstile(), שמתחילה במצב נעול ומחזירה את handle(event) (התשובה, או ignored במקרה של אירוע לא מוכר), את state() ואת passes(). ספרו מעבר בכל פעם ש-push מטופל במצב הפתוח. הקוד שסופק קורא אירועים ומדפיס כל תשובה לצד המצב החדש, ולאחר מכן את מספר המעברים.
כתבו את הקוד שלכם ב-Turnstile.R. הקובץ main.R מכיל את קוד הקלט/פלט שסופק, ואי אפשר לערוך אותו.
נסו בעצמכם
source("Turnstile.R")
# קוד הקלט/פלט שסופק: יש להשאיר אותו כפי שהוא
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 = "")
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה תכנות מונחה עצמים
1יסודות S3
עבודה עם קבציםרשימות עם מחלקהפונקציות בנאימתודות print ו-formatמאמתים ופונקציות עזרחזרה – טמפרטורותתרגלו בעצמכם: קומפיילר R אונליין