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

التوسعة باستخدام NextMethod

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

غالبًا ما تنفّذ طريقة الابن عمل طريقة الأب بالإضافة إلى القليل من العمل. تستدعي NextMethod() طريقة الأب، لذا يضيف الابن ما هو جديد فقط. الأجر الشهري للمدير هو أجر الموظف مضافًا إليه المكافأة:

pay <- function(x) UseMethod("pay")
pay.employee <- function(x) x$salary / 12
pay.manager <- function(x) NextMethod() + x$bonus / 12
m <- structure(list(salary = 60000, bonus = 12000), class = c("manager", "employee"))
e <- structure(list(salary = 36000), class = "employee")
cat(pay(e), pay(m))

الناتج:

3000 6000

تواصل NextMethod() العمل عبر عدة مستويات. تضيف كل طريقة جزءها وتُمرِّر التنفيذ إلى الفئة التي تلي فئتها:

pay <- function(x) UseMethod("pay")
pay.employee <- function(x) x$salary / 12
pay.manager <- function(x) NextMethod() + x$bonus / 12
pay.director <- function(x) NextMethod() + 500
d <- structure(list(salary = 120000, bonus = 24000),
               class = c("director", "manager", "employee"))
print(pay(d))

الناتج:

[1] 12500

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

withdraw <- function(acc, amount) UseMethod("withdraw")
withdraw.account <- function(acc, amount) {
  if (amount > acc$balance) stop("insufficient funds", call. = FALSE)
  acc$balance <- acc$balance - amount
  acc
}
withdraw.savings <- function(acc, amount) {
  if (amount > 500) stop("savings limit is 500", call. = FALSE)
  NextMethod()
}
s <- structure(list(balance = 1000), class = c("savings", "account"))
s <- withdraw(s, 200)
cat(s$balance, class(s))

الناتج:

800 savings account

تعيد المُنشئات والأساليب استخدام الصنف الأب بالطريقة نفسها: تستدعي new_manager() الدالة new_employee()، وتستدعي pay.manager() الدالة NextMethod(). يُكتب كود الموظف مرة واحدة، ويبني كل صنف فرعي عليه:

new_manager <- function(name, salary, bonus) {
  new_employee(name, salary, bonus = bonus, class = "manager")   # إعادة استخدام المُنشئ
}
pay.manager <- function(x) NextMethod() + x$bonus / 12            # إعادة استخدام الطريقة
challenge icon

التحدي

سهل

الحسابات وحسابات التوفير موجودة في ملفين. في Account.R أكمل withdraw.account(acc, amount)، التي تتوقف مع insufficient funds عندما يكون المبلغ أكبر من الرصيد، وإلا تُرجع الحساب مع الرصيد الأقل، وformat.account()، التي تُرجع ada: 800. في Savings.R أكمل withdraw.savings()، التي تتوقف مع savings limit is 500 للمبالغ الأكبر من 500، وإلا تتابع باستخدام NextMethod()، وformat.savings()، التي تُرجع ada: 800 (savings) من خلال استدعاء NextMethod().

استخدم call. = FALSE. الدالة العامة والمنشئات معطاة. يقرأ الكود المقدم savings ada 1000 أو account bo 300، ثم مبالغ السحب؛ ويطبع withdrew 200 أو refused: والرسالة، وأخيرًا الحساب المنسق.

ضع الكود في Account.R وSavings.R. يحتوي main.R على كود الإدخال/الإخراج المقدم ولا يمكن تعديله.

جرّب بنفسك

source("Account.R")
source("Savings.R")

# كود الإدخال/الإخراج المُزوَّد: اتركه كما هو
input <- suppressWarnings(readLines(file("stdin")))
p <- strsplit(input[1], " ")[[1]]
acc <- if (p[1] == "savings") new_savings(p[2], as.numeric(p[3])) else new_account(p[2], as.numeric(p[3]))
for (amount in as.numeric(input[-1])) {
  acc <- tryCatch({
    acc <- withdraw(acc, amount)
    cat("withdrew ", amount, "\n", sep = "")
    acc
  }, error = function(e) {
    cat("refused: ", conditionMessage(e), "\n", sep = "")
    acc
  })
}
cat(format(acc), "\n", sep = "")
quiz iconاختبر نفسك

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

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

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