דפוס Decorator
חלק מהיחידה תכנות מונחה עצמים במסלול ה-Ruby של Coddy. שיעור 47 מתוך 57.
תבנית הdecorator עוטפת אובייקט באובייקט אחר בעל אותו ממשק, וכך מוסיפה משהו לפני העברת הקריאה הלאה או אחריה. אפשר לשרשר עוטפים בכל סדר:
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
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה תכנות מונחה עצמים
3מתודות ומשתנים של מחלקה
מתודות של מחלקהמשתני מופע של מחלקהקבועיםמתודות ליצירת מופעיםסיכום – קודי קופוןתרגלו בעצמכם: קומפיילר Ruby אונליין