نمط الديكور
جزء من قسم البرمجة كائنية التوجه في رحلة 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!التحدي
سهلتُزيَّن المشروبات بإضافات. يحتوي 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 = "")
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس البرمجة كائنية التوجه
1أساسيات S3
التعامل مع الملفاتالقوائم باستخدام فئةدوال المُنشئأساليب الطباعة والتنسيقأدوات التحقق والمساعدةمراجعة - درجات الحرارة2S3 الدوال العامة والطرق
الدوال العامة وUseMethodالطرق الافتراضيةطرق الدوال العامة الأساسيةأساسيات NextMethodمراجعة - مساحات الأشكالتدرّب بنفسك: مترجم R عبر الإنترنت