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