نمط المزيّن
جزء من قسم البرمجة كائنية التوجه في رحلة Ruby على Coddy. الدرس 47 من 57.
يقوم نمط المُزَيِّن بتغليف كائن داخل كائن آخر له الواجهة نفسها، ما يضيف شيئًا قبل تمرير الاستدعاء أو بعده. ويمكن تكديس المُزَيِّنات بأي ترتيب:
class Coffee
def cost
2.0
end
def description
"coffee"
end
end
class Milk
def initialize(drink)
@drink = drink
end
def cost
@drink.cost + 0.5
end
def description
"#{@drink.description}, milk"
end
end
order = Milk.new(Milk.new(Coffee.new))
puts format("%s: %.2f", order.description, order.cost)الناتج:
coffee, milk, milk: 3.00يخزّن كل مُزيّن الكائنَ الذي يغلّفه ويفوّض إليه، لذا يمكن لصنف أساسي مشترك أن يتولى هذا الجزء. ثم يتجاوز كل مُزيّن ملموس فقط ما يغيّره:
class Coffee
def cost
2.0
end
def description
"coffee"
end
end
class Extra
def initialize(drink)
@drink = drink
end
def cost
@drink.cost
end
def description
@drink.description
end
end
class Sugar < Extra
def cost
super + 0.2
end
def description
super + ", sugar"
end
end
order = Sugar.new(Coffee.new)
puts format("%s: %.2f", order.description, order.cost)الناتج:
coffee, sugar: 2.20تُمرِّر المكتبة القياسية SimpleDelegator (require 'delegate') كلَّ طريقة لا تعرّفها إلى الكائن المُغلَّف، مما يُبقي الزخارف قصيرة عندما تكون الواجهة كبيرة:
require 'delegate'
class Loud < SimpleDelegator
def to_s
super.upcase + "!"
end
end
text = Loud.new("hello")
puts text
puts text.size
puts text.start_with?("he")الناتج:
HELLO!
5
trueتضيف المُزيّنات سلوكًا إلى كائنات مفردة وقت التشغيل، ويمكن دمجها بحرية. أما مع الفئات الفرعية، فستحتاج كل مجموعة، مثل MilkSugarCoffee، إلى فئة خاصة بها:
Sugar.new(Milk.new(Coffee.new)) # أي تركيبة، بأي ترتيب
Whip.new(Sugar.new(Coffee.new))
# باستخدام الفئات الفرعية: MilkCoffee, SugarCoffee, MilkSugarCoffee, ...التحدي
سهلأكمل مُزيّنات القهوة. تكلفة Coffee هي 2.00 ووصفها هو coffee. تضيف Milk مقدار 0.50 و, milk، وتضيف Sugar مقدار 0.20 و, sugar، وتضيف Whip مقدار 0.70 و, whip. تشترك المُزيّنات الثلاثة في الصنف الأساسي Extra، الذي يخزّن المشروب المُغلّف ويمرّر cost وdescription؛ ويستخدم كل صنف فرعي super.
كل سطر إدخال هو طلب، مثل milk sugar. يغلّف الكود المُرفق كائنًا جديدًا من Coffee بالمُزيّنات حسب ذلك الترتيب، ثم يطبع coffee, milk, sugar: 2.70.
ضع الكود في coffee.rb وextra.rb وmilk.rb وsugar.rb وwhip.rb. يحتوي main.rb على كود الإدخال والإخراج المُرفق، ولا يمكن تعديله.
جرّب بنفسك
require_relative 'coffee'
require_relative 'extra'
require_relative 'milk'
require_relative 'sugar'
require_relative 'whip'
# كود الإدخال/الإخراج المقدم: أبقه كما هو
input = []
while (line = gets)
input << line.chomp
end
extras = { "milk" => Milk, "sugar" => Sugar, "whip" => Whip }
input.each do |line|
drink = line.split.reduce(Coffee.new) { |d, name| extras[name].new(d) }
puts format("%s: %.2f", drink.description, drink.cost)
end
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس البرمجة كائنية التوجه
1الفئات والكائنات
العمل مع الملفاتتعريف الفئاتمتغيرات النسخةالأساليب و selfto_s و inspectمراجعة - بطاقة المكتبة7تعدد الأشكال والكتابة بأسلوب البطة
تعدد الأشكالالكتابة بأسلوب البطةالأساليب المجردةالحالات والفئاتمراجعة - طرق الدفع3أساليب ومتغيرات الأصناف
أساليب الأصنافمتغيرات كائنات الأصنافالثوابتأساليب الإنشاءمراجعة - رموز القسائمتدرّب بنفسك: مترجم Ruby عبر الإنترنت