Шаблон Singleton
Часть раздела Объектно-ориентированное программирование путешествия по R на Coddy. Урок 42 из 57.
Шаблон проектирования — это проверенное решение задачи проектирования, которая возникает снова и снова. Шаблон одиночка гарантирует наличие ровно одного экземпляра чего-либо, доступного из любого места. В 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 (тип character, изначально пустое). Затем напишите:
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Валидаторы и вспомогательные функцииПовторение — температуры4Инкапсуляция в R
Замыкания как объектыОкружения как объектыФункции доступаЗащита состоянияПовторение — парковочный счётчик7S4 Наследование
Расширение с помощью containscallNextMethodВиртуальные классыПроверка типов с помощью is()Повторение — смотритель зоопарка10Шаблоны проектирования, часть 2
Шаблон «Декоратор»Шаблон «Строитель»Шаблон «Состояние»Шаблон «Итератор»2Обобщённые функции и методы S3
Обобщённые функции и UseMethodМетоды по умолчаниюМетоды для базовых обобщённых функцийОсновы NextMethodПовторение — площади фигур5Классы S4
Определение классов S4Слоты и доступПроверка корректностиМетоды showПовторение — каталог товаров8Ссылочные классы
Определение ссылочных классовМетоды и обновление полейСемантика копированияНаследование и callSuperПовторение — очередь задач11Проект: Управление библиотекой
Книги и читателиВыдача книг3Наследование S3
Векторы классовПорядок поиска методовРасширение с помощью NextMethodПроверка с помощью inherits()Повторение — расчёт зарплаты сотрудниковПотренируйтесь самостоятельно: Онлайн-компилятор R