Menu
Coddy logo textTech

Gözlemci Kalıbı

Coddy'nin R Journey'sinin Nesne Tabanlı Programlama bölümünün bir parçası. Ders 44 / 57.

observer deseni, subject olarak adlandırılan bir nesnenin, ne zaman bir şey olduğunu kimin dinlediğini bilmeden diğer kodlara bildirmesini sağlar. Subject, callback işlevlerinin (observer'ların) bir listesini tutar ve her olayda bunların her birini çağırır:

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")

Çıktı:

logger saw click 
counter saw click 

Bir gözlemci, kendi durumuna sahip bir kapanış olabilir. Bu kapanış gördüğü olayları sayarken, konu sayma hakkında hiçbir şey bilmez:

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())

Çıktı:

[1] 3

Gözlemcileri adlar altında saklamak, abonelikten çıkmalarına olanak tanır. observers[[name]] <<- NULL birini kaldırır ve diğerleri olayları almaya devam eder:

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")

Çıktı:

ada: first 
bo: first 
bo: second 

Özne, bir olayın hangi verileri taşıyacağını belirler. Bir fiyat göstergesi eski ve yeni fiyatı iletir ve yalnızca fiyat gerçekten değiştiğinde bildirimde bulunur:

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)

Çıktı:

price 10 -> 12 
price 12 -> 9 
challenge icon

Görev

Kolay

make_newsletter() fabrikasını Newsletter.R içinde tamamla. Okuyucularının geri çağırmalarını özel bir adlandırılmış listede tutar ve üç işlev döndürür:

  • subscribe(name, f) geri çağırmayı adın altında saklar (yeniden abone olmak mevcut kaydın yerini alır);
  • unsubscribe(name) kaydı kaldırır;
  • publish(title) her geri çağırmayı başlıkla, abonelik sırasına göre çağırır ve bildirim gönderilenlerin sayısını döndürür.

Sağlanan kod sub ada, unsub ada ve post Big news komutlarını okur ve her okuyucuya ada got: Big news yazdıran bir geri çağırma verir. Her gönderi için başlığı, geri çağırmaların satırlarını ve bildirim gönderilenlerin sayısını yazdırır.

Kodun Newsletter.R içine yazılmalıdır. main.R sağlanan girdi/çıktı kodunu içerir ve düzenlenemez.

Kendin dene

source("Newsletter.R")

# Sağlanan girdi/çıktı kodu: olduğu gibi bırakın
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 = "")
  }
}
quiz iconKendini test et

Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.

Nesne Tabanlı Programlama bölümündeki tüm dersler

Kendi başına pratik yap: Online R derleyicisi