Menu
Coddy logo textTech

Функции доступа

Часть раздела Объектно-ориентированное программирование путешествия по R на Coddy. Урок 19 из 57.

Инкапсуляция означает, что другой код работает с объектом через функции, а не обращается напрямую к его полям. Геттер считывает значение, а сеттер изменяет его. Для списка S3 сеттер возвращает изменённую копию:

new_member <- function(name) structure(list(name = name), class = "member")
get_name <- function(p) p$name
set_name <- function(p, value) {
  p$name <- value
  p
}
p <- new_member("ada")
p <- set_name(p, "Ada Lovelace")
print(get_name(p))

Результат:

[1] "Ada Lovelace"

Аксессоры позволяют объекту изменять способ хранения данных, не нарушая код, который его использует. Этот термометр хранит температуру в градусах Цельсия, а геттер вычисляет градусы Фаренгейта по запросу, поэтому вызывающий код никогда не видит само поле:

new_thermo <- function(c) structure(list(c = c), class = "thermo")
celsius <- function(t) t$c
fahrenheit <- function(t) t$c * 9 / 5 + 32
t <- new_thermo(25)
cat(celsius(t), fahrenheit(t))

Вывод:

25 77

Собственные сеттеры R, такие как names(x) <- ..., являются функциями замены. Функция с именем "name<-" и параметрами x и value позволяет вызывающему коду записать name(p) <- "Bo"; R вызывает её и присваивает результат обратно p:

new_member <- function(name) structure(list(name = name), class = "member")
name <- function(p) p$name
"name<-" <- function(x, value) {
  x$name <- trimws(value)
  x
}
p <- new_member("ada")
name(p) <- "  Bo  "
print(name(p))

Вывод:

[1] "Bo"

Геттер объекта-замыкания возвращает копию приватных данных. Изменение этой копии не изменяет объект, поэтому попасть внутрь можно только через собственные функции объекта:

make_list <- function() {
  items <- character(0)
  list(add = function(x) items <<- c(items, x),
       get_items = function() items)
}
todo <- make_list()
todo$add("milk")
mine <- todo$get_items()
mine[1] <- "HACKED"
print(todo$get_items())

Вывод:

[1] "milk"
challenge icon

Задание

Легко

Контакт — это список S3 класса contact с полями name и email. Дополните Contact.R:

  • new_contact(name, email) сохраняет email после удаления пробелов и в нижнем регистре.
  • Геттеры contact_name(x) и contact_email(x).
  • Функция замены "contact_email<-", которая сохраняет новый email после удаления пробелов и в нижнем регистре, чтобы вызывающий код мог использовать запись contact_email(c1) <- value.

Предоставленный код считывает name,email, затем новые адреса email и после каждого изменения выводит Ada <ada@x.com>, а в конце — имена сохранённых полей.

Ваш код должен находиться в Contact.R. В main.R содержится предоставленный код ввода/вывода, и его нельзя редактировать.

Попробуйте сами

source("Contact.R")

# Предоставленный код ввода/вывода: оставьте его как есть
input <- suppressWarnings(readLines(file("stdin")))
p <- strsplit(input[1], ",")[[1]]
c1 <- new_contact(p[1], p[2])
cat(contact_name(c1), " <", contact_email(c1), ">\n", sep = "")
for (value in input[-1]) {
  contact_email(c1) <- value
  cat(contact_name(c1), " <", contact_email(c1), ">\n", sep = "")
}
cat("stored fields: ", paste(names(unclass(c1)), collapse = ", "), "\n", sep = "")
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование

Потренируйтесь самостоятельно: Онлайн-компилятор R