Menu
CoddyTech

Pola Decorator

Termasuk bagian Pemrograman Berorientasi Object dalam perjalanan R di Coddy. Pelajaran 46 dari 57.

Dekorator membungkus sesuatu dan menambahkan perilaku sambil mempertahankan antarmuka yang sama. Untuk fungsi, dekorator menerima sebuah fungsi dan mengembalikan fungsi baru yang melakukan pekerjaan tambahan saat fungsi dipanggil:

with_logging <- function(f, name) {
  function(x) {
    cat("calling", name, "with", x, "\n")
    f(x)
  }
}
double <- function(x) x * 2
logged <- with_logging(double, "double")
print(logged(21))

output:

calling double with 21 
[1] 42

Dekorator dapat mengingat hasil. with_cache() menyimpan setiap jawaban di dalam environment dan memanggil fungsi yang dibungkus hanya untuk argumen baru:

with_cache <- function(f) {
  cache <- new.env()
  function(x) {
    key <- as.character(x)
    if (!exists(key, envir = cache, inherits = FALSE)) assign(key, f(x), envir = cache)
    get(key, envir = cache)
  }
}
work <- 0
slow_square <- function(x) {
  work <<- work + 1
  x^2
}
fast <- with_cache(slow_square)
for (x in c(3, 4, 3, 3, 4)) fast(x)
cat("results computed:", work)

Output:

results computed: 2

Object juga bisa dihias. Setiap decorator adalah object yang menyimpan object yang dibungkusnya dalam sebuah field dan merespons generik yang sama, dengan menambahkan bagiannya dan meminta object di dalamnya untuk sisanya:

cost <- function(d) UseMethod("cost")
describe <- function(d) UseMethod("describe")
cost.coffee <- function(d) 2
describe.coffee <- function(d) "coffee"
with_milk <- function(inner) structure(list(inner = inner), class = "milk")
cost.milk <- function(d) cost(d$inner) + 0.5
describe.milk <- function(d) paste(describe(d$inner), "+ milk")
cup <- with_milk(with_milk(structure(list(), class = "coffee")))
cat(describe(cup), "=", cost(cup))

Output:

coffee + milk + milk = 3

Dekorator dapat ditumpuk, dan urutannya penting: dekorator terluar dijalankan pertama saat proses masuk dan terakhir saat proses keluar:

exclaim <- function(f) function(s) paste0(f(s), "!")
twice <- function(f) function(s) paste(f(s), f(s))
greet <- function(name) paste("hi", name)
a <- twice(exclaim(greet))
b <- exclaim(twice(greet))
cat(a("ada"), "/", b("ada"))

Output:

hi ada! hi ada! / hi ada hi ada!
challenge icon

Tantangan

Mudah

Minuman dihias dengan tambahan. Drink.R berisi fungsi generik cost() dan describe(), serta minuman dasar, new_coffee(), yang harganya 2 dan mendeskripsikan dirinya sebagai coffee. Di Extras.R, tulis tiga decorator, masing-masing berupa object yang menyimpan minuman yang dibungkusnya di field inner:

  • add_milk(d): class milk, menambahkan 0.50 dan + milk;
  • add_sugar(d): class sugar, menambahkan 0.20 dan + sugar;
  • add_syrup(d, flavour): class syrup dengan field flavour, menambahkan 0.80 dan + vanilla syrup.

Tulis method cost() dan describe() untuk masing-masing dengan meminta minuman di dalamnya terlebih dahulu. Kode yang disediakan membaca baris seperti milk,syrup vanilla,sugar (baris kosong berarti kopi biasa) dan mencetak coffee + milk + vanilla syrup + sugar: 3.50.

Tulis kodemu di Drink.R dan Extras.R. main.R berisi kode input/output yang disediakan dan tidak boleh diedit.

Coba sendiri

source("Drink.R")
source("Extras.R")

# Kode input/output yang disediakan: biarkan apa adanya
input <- suppressWarnings(readLines(file("stdin")))
for (line in input) {
  d <- new_coffee()
  if (nchar(line) > 0) for (extra in strsplit(line, ",")[[1]]) {
    p <- strsplit(extra, " ")[[1]]
    d <- switch(p[1], milk = add_milk(d), sugar = add_sugar(d), syrup = add_syrup(d, p[2]))
  }
  cat(sprintf("%s: %.2f", describe(d), cost(d)), "\n", sep = "")
}
quiz iconUji dirimu

Pelajaran ini berisi kuis singkat. Mulai pelajarannya untuk menjawab kuis dan melacak progresmu.

Semua pelajaran di Pemrograman Berorientasi Object

Latihan sendiri: Compiler R online