תבנית Singleton
חלק מהיחידה תכנות מונחה עצמים במסלול ה-R של Coddy. שיעור 42 מתוך 57.
תבנית עיצוב היא פתרון מוכח לבעיית עיצוב שחוזרת שוב ושוב. תבנית singleton מוודאת שיש בדיוק מופע אחד של דבר כלשהו, שאפשר לגשת אליו מכל מקום. ב-R, פונקציית גישה יוצרת את המופע בקריאה הראשונה אליה, שומרת אותו במשתנה שנוצר באמצעות local(), ומחזירה את אותו מופע בכל פעם:
get_config <- local({
instance <- NULL
function() {
if (is.null(instance)) {
instance <<- new.env()
instance$theme <- "light"
}
instance
}
})
a <- get_config()
a$theme <- "dark"
b <- get_config()
cat(b$theme, identical(a, b))פלט:
dark TRUEהמופע הוא סביבה, לכן שינוי שנעשה באמצעות קריאה אחת גלוי לכל חלק אחר של התוכנית. שתי פונקציות במקומות שונים כותבות לאותו יומן:
get_log <- local({
instance <- NULL
function() {
if (is.null(instance)) {
instance <<- new.env()
instance$lines <- character(0)
}
instance
}
})
page_a <- function() {
log <- get_log()
log$lines <- c(log$lines, "a visited")
}
page_b <- function() {
log <- get_log()
log$lines <- c(log$lines, "b visited")
}
page_a()
page_b()
page_a()
print(get_log()$lines)פלט:
[1] "a visited" "b visited" "a visited"המופע נוצר רק כאשר הוא נדרש לראשונה. ספירת היצירות מראה שזה קורה פעם אחת, בלי קשר למספר הפעמים שבהן נקראת פונקציית הגישה:
created <- 0
get_db <- local({
instance <- NULL
function() {
if (is.null(instance)) {
created <<- created + 1
instance <<- new.env()
}
instance
}
})
for (i in 1:5) db <- get_db()
cat("created", created, "time(s)")פלט:
created 1 time(s)השתמשו בסינגלטונים במידה מועטה. סינגלטון הוא מצב גלובלי: כל קוד יכול לשנות אותו, ובדיקה לא יכולה להתחיל מעותק נקי בלי לאפס אותו. הוא מתאים לדברים שיש מהם באמת רק אחד בכל התוכנית, כמו מתעד או ההגדרות; לעיתים קרובות, העברת אובייקט כארגומנט ברורה יותר:
# קל יותר לבדוק: ה-log מועבר כארגומנט
process <- function(order, log) {
log$lines <- c(log$lines, paste("processing", order$id))
}אתגר
קלהשלם את הלוגר היחיד ב־Logger.R. הפונקציה get_logger() מחזירה סביבה אחת, שנוצרת בקריאה הראשונה, עם השדה entries (מחרוזת, ריקה בהתחלה). לאחר מכן כתוב:
- את
log_info(msg)ואתlog_error(msg), שמוסיפות את[INFO] msgאו את[ERROR] msgלרשומות של הלוגר המשותף; - את
error_count(), שסופרת את הרשומות שמתחילות ב־[ERROR].
הקוד שסופק קורא שורות info,started או error,disk full, רושם כל אחת מהן, ואז מדפיס כל רשומה, את מספר השגיאות, והאם שתי קריאות ל־get_logger() מחזירות את אותו אובייקט.
הקוד שלך יופיע ב־Logger.R. הקובץ main.R מכיל את קוד הקלט/פלט שסופק ואי אפשר לערוך אותו.
נסו בעצמכם
source("Logger.R")
# קוד הקלט/פלט שסופק: השאירו אותו כפי שהוא
input <- suppressWarnings(readLines(file("stdin")))
for (line in input) {
p <- strsplit(line, ",")[[1]]
if (p[1] == "error") log_error(p[2]) else log_info(p[2])
}
for (e in get_logger()$entries) cat(e, "\n", sep = "")
cat("errors: ", error_count(), "\n", sep = "")
cat("one logger: ", identical(get_logger(), get_logger()), "\n", sep = "")
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה תכנות מונחה עצמים
1יסודות S3
עבודה עם קבציםרשימות עם מחלקהפונקציות בנאימתודות print ו-formatמאמתים ופונקציות עזרחזרה – טמפרטורותתרגלו בעצמכם: קומפיילר R אונליין