Padrão Observer
Parte da seção Programação Orientada a Objetos do Journey de R da Coddy. Lição 44 de 57.
O padrão observer permite que um objeto, o subject, informe a outro código quando algo acontece sem saber quem está ouvindo. O subject mantém uma lista de funções de callback, os observers, e chama cada uma delas a cada evento:
make_subject <- function() {
observers <- list()
list(
subscribe = function(f) observers[[length(observers) + 1]] <<- f,
notify = function(event) for (f in observers) f(event)
)
}
button <- make_subject()
button$subscribe(function(e) cat("logger saw", e, "\n"))
button$subscribe(function(e) cat("counter saw", e, "\n"))
button$notify("click")Saída:
logger saw click
counter saw click Un observador puede ser un cierre con su propio estado. Este cuenta los eventos que ha visto, mientras que el sujeto no sabe nada sobre el conteo:
make_subject <- function() {
observers <- list()
list(subscribe = function(f) observers[[length(observers) + 1]] <<- f,
notify = function(event) for (f in observers) f(event))
}
make_counter <- function() {
n <- 0
list(observe = function(event) n <<- n + 1, count = function() n)
}
door <- make_subject()
c1 <- make_counter()
door$subscribe(c1$observe)
for (e in c("open", "close", "open")) door$notify(e)
print(c1$count())Salida:
[1] 3Armazenar observadores sob nomes permite que eles cancelem a inscrição. observers[[name]] <<- NULL remove um, e os outros continuam recebendo eventos:
make_subject <- function() {
observers <- list()
list(
subscribe = function(name, f) observers[[name]] <<- f,
unsubscribe = function(name) observers[[name]] <<- NULL,
notify = function(event) for (f in observers) f(event)
)
}
s <- make_subject()
s$subscribe("ada", function(e) cat("ada:", e, "\n"))
s$subscribe("bo", function(e) cat("bo:", e, "\n"))
s$notify("first")
s$unsubscribe("ada")
s$notify("second")Saída:
ada: first
bo: first
bo: second O assunto determina quais dados um evento carrega. Um ticker de preços passa o preço antigo e o novo, e notifica somente quando o preço realmente muda:
make_ticker <- function(price) {
observers <- list()
list(
subscribe = function(f) observers[[length(observers) + 1]] <<- f,
set_price = function(new) {
if (new == price) return(invisible(NULL))
old <- price
price <<- new
for (f in observers) f(old, new)
}
)
}
t <- make_ticker(10)
t$subscribe(function(old, new) cat("price", old, "->", new, "\n"))
for (p in c(12, 12, 9)) t$set_price(p)Saída:
price 10 -> 12
price 12 -> 9 Desafio
FácilComplete a fábrica make_newsletter() em Newsletter.R. Ela mantém os callbacks dos leitores em uma lista nomeada privada e retorna três funções:
subscribe(name, f)armazena o callback sob o nome (inscrever-se novamente o substitui);unsubscribe(name)o remove;publish(title)chama cada callback com o título, na ordem de inscrição, e retorna quantos foram notificados.
O código fornecido lê os comandos sub ada, unsub ada e post Big news, e fornece a cada leitor um callback que imprime ada got: Big news. Para cada publicação, ele imprime o título, as linhas dos callbacks e o número de notificações.
Seu código deve ficar em Newsletter.R. main.R contém o código fornecido de entrada/saída e não pode ser editado.
Experimente você mesmo
source("Newsletter.R")
# Código de entrada/saída fornecido: mantenha-o como está
input <- suppressWarnings(readLines(file("stdin")))
news <- make_newsletter()
reader <- function(name) {
force(name)
function(title) cat(" ", name, " got: ", title, "\n", sep = "")
}
for (line in input) {
p <- strsplit(line, " ")[[1]]
if (p[1] == "sub") news$subscribe(p[2], reader(p[2]))
if (p[1] == "unsub") news$unsubscribe(p[2])
if (p[1] == "post") {
title <- paste(p[-1], collapse = " ")
cat("post: ", title, "\n", sep = "")
n <- news$publish(title)
cat(" notified ", n, "\n", sep = "")
}
}
Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Programação Orientada a Objetos
1Fundamentos do S3
Trabalhando com ArquivosListas com uma ClasseFunções ConstrutorasMétodos de Impressão e FormataçãoValidadores e AuxiliaresRevisão - Temperaturas4Encapsulamento em R
Closures como ObjetosAmbientes como ObjetosFunções de AcessoProtegendo o EstadoRecapitulação - Parquímetro2Genéricos e Métodos S3
Genéricos e UseMethodMétodos padrãoMétodos para genéricos baseFundamentos de NextMethodRevisão - Áreas de formas5Classes S4
Definindo classes S4Slots e acessoVerificações de validadeMétodos showRevisão - Catálogo de produtos8Classes de Referência
Definindo Classes de ReferênciaMétodos e Atualizações de CamposSemântica de CópiaHerança e callSuperRecapitulação — Fila de Tarefas11Projeto: Gerenciamento de Biblioteca
Livros e MembrosEmpréstimo de LivrosPratique por conta própria: Compilador de R online