نمط الحالة
جزء من قسم البرمجة كائنية التوجه في رحلة 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
التعامل مع الملفاتالقوائم باستخدام فئةدوال المُنشئأساليب الطباعة والتنسيقأدوات التحقق والمساعدةمراجعة - درجات الحرارة2S3 الدوال العامة والطرق
الدوال العامة وUseMethodالطرق الافتراضيةطرق الدوال العامة الأساسيةأساسيات NextMethodمراجعة - مساحات الأشكالتدرّب بنفسك: مترجم R عبر الإنترنت