Menu
Coddy logo textTech
flag Ar iconالعربيةdown icon

نمط الديكور

جزء من قسم البرمجة كائنية التوجه في رحلة R على Coddy. الدرس 46 من 57.

يلفّ المزيّن شيئًا ما ويضيف سلوكًا مع الحفاظ على الواجهة نفسها. بالنسبة إلى دالة، يأخذ المزيّن دالةً ويُرجع دالةً جديدةً تنفّذ عملًا إضافيًا حول الاستدعاء:

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

الناتج:

calling double with 21 
[1] 42

يمكن للمزخرف تذكّر النتائج. تحتفظ with_cache() بكل إجابة في بيئة، ولا تستدعي الدالة المُغلّفة إلا للوسائط الجديدة:

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)

المخرجات:

results computed: 2

يمكن تزيين الكائنات أيضًا. كل مُزيّن هو كائن يحتفظ بالكائن الذي يغلّفه في حقل ويستجيب للواجهات العامة نفسها، مضيفًا الجزء الخاص به وطالبًا من الكائن الداخلي تنفيذ الجزء المتبقي:

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

الناتج:

coffee + milk + milk = 3

تتراكم المُزخرفات، ويهم ترتيبها: يُنفَّذ المُزخرف الخارجي أولًا عند الدخول وآخرًا عند الخروج:

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

الناتج:

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

التحدي

سهل

تُزيَّن المشروبات بإضافات. يحتوي Drink.R على الدالتين العامتين cost() وdescribe() والمشروب الأساسي new_coffee()، الذي تكلفته 2 ويصف نفسه بأنه coffee. في Extras.R اكتب ثلاثة مُزيِّنات، كلٌّ منها كائن يحتفظ بالمشروب الذي يغلّفه في الحقل inner:

  • add_milk(d): الفئة milk، تضيف 0.50 و + milk؛
  • add_sugar(d): الفئة sugar، تضيف 0.20 و + sugar؛
  • add_syrup(d, flavour): الفئة syrup مع الحقل flavour، تضيف 0.80 و + vanilla syrup.

اكتب طريقتَي cost() وdescribe() الخاصة بها باستدعاء المشروب الداخلي أولًا. يقرأ الكود المزوَّد أسطرًا مثل milk,syrup vanilla,sugar (السطر الفارغ يعني قهوة سادة) ويطبع coffee + milk + vanilla syrup + sugar: 3.50.

ضع الكود الخاص بك في Drink.R وExtras.R. يحتوي main.R على كود الإدخال/الإخراج المزوَّد، ولا يمكن تعديله.

جرّب بنفسك

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

# كود الإدخال/الإخراج المُزوَّد: اتركه كما هو
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 iconاختبر نفسك

يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.

جميع دروس البرمجة كائنية التوجه

تدرّب بنفسك: مترجم R عبر الإنترنت