Mẫu Observer
Thuộc phần Lập trình hướng đối tượng trong hành trình R của Coddy. Bài học 44 trên 57.
Mẫu observer cho phép một đối tượng, gọi là subject, thông báo cho đoạn code khác khi có sự kiện xảy ra mà không cần biết ai đang lắng nghe. Subject giữ một danh sách các hàm callback, gọi là các observer, và gọi từng hàm khi có sự kiện:
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")Đầu ra:
logger saw click
counter saw click Một observer có thể là một closure với trạng thái riêng. Observer này đếm các sự kiện mà nó đã thấy, còn subject không biết gì về việc đếm:
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())Đầu ra:
[1] 3Lưu các observer dưới tên giúp chúng hủy đăng ký. observers[[name]] <<- NULL xóa một observer, còn những observer khác vẫn tiếp tục nhận sự kiện:
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")Đầu ra:
ada: first
bo: first
bo: second Chủ đề quyết định sự kiện mang theo dữ liệu nào. Một bộ theo dõi giá truyền giá cũ và giá mới, đồng thời chỉ thông báo khi giá thực sự thay đổi:
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)Đầu ra:
price 10 -> 12
price 12 -> 9 Thử thách
DễHoàn thiện hàm factory make_newsletter() trong Newsletter.R. Hàm này lưu các callback của độc giả trong một danh sách có tên riêng tư và trả về ba hàm:
subscribe(name, f)lưu callback dưới tên đó (nếu đăng ký lại, callback cũ sẽ được thay thế);unsubscribe(name)xóa callback đó;publish(title)gọi từng callback với tiêu đề, theo thứ tự đăng ký, rồi trả về số độc giả đã được thông báo.
Code được cung cấp đọc các lệnh sub ada, unsub ada và post Big news, rồi tạo cho mỗi độc giả một callback in ra ada got: Big news. Với mỗi bài đăng, code in tiêu đề, các dòng do callback in ra và số độc giả đã được thông báo.
Code của bạn nằm trong Newsletter.R. main.R chứa code đầu vào/đầu ra được cung cấp và bạn không thể chỉnh sửa tệp này.
Tự làm thử
source("Newsletter.R")
# Đoạn code đầu vào/đầu ra được cung cấp sẵn: giữ nguyê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 = "")
}
}
Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.
Tất cả bài học trong Lập trình hướng đối tượng
1Kiến thức cơ bản về S3
Làm việc với tệpDanh sách với một lớpHàm khởi tạoPhương thức in ra và định dạngTrình xác thực và hàm hỗ trợÔn tập: nhiệt độ4Tính đóng gói trong R
Closure dưới dạng đối tượngMôi trường dưới dạng đối tượngHàm truy cậpBảo vệ trạng tháiÔn tập: đồng hồ tính phí đỗ xe2S3, hàm generic và phương thức
Hàm generic và UseMethodPhương thức mặc địnhPhương thức cho hàm generic cơ sởCơ bản về NextMethodÔn tập: diện tích hình5Các lớp S4
Định nghĩa lớp S4Slot và quyền truy cậpKiểm tra tính hợp lệPhương thức showÔn tập: Danh mục sản phẩmTự luyện tập: Trình biên dịch R online