תבנית Strategy
חלק מהיחידה תכנות מונחה עצמים במסלול ה-Ruby של Coddy. שיעור 45 מתוך 57.
תבנית האסטרטגיה מעבירה חלק אחד מאלגוריתם לאובייקט משלו ומאפשרת לאובייקט הראשי להאציל לו את העבודה. החלפת האסטרטגיה משנה את ההתנהגות בלי לשנות את המחלקה הראשית:
class Standard
def cost(kg)
5 + kg * 1.5
end
end
class Express
def cost(kg)
15 + kg * 3
end
end
class Shipment
attr_writer :strategy
def initialize(kg, strategy)
@kg = kg
@strategy = strategy
end
def cost
@strategy.cost(@kg)
end
end
s = Shipment.new(2, Standard.new)
puts s.cost
s.strategy = Express.new
puts s.costפלט:
8.0
21האסטרטגיות חולקות רק שם של מתודה, לכן כל אובייקט שיש לו cost יעבוד: שוב, טיפוסיות ברווז. הוספת דרך חדשה למשלוח פירושה הוספת מחלקה אחת, ולא ענף נוסף בתוך Shipment:
class Pickup
def cost(_kg)
0
end
end
shipment.strategy = Pickup.new # Shipment לא השתנהב-Ruby, אסטרטגיה היא לעיתים קרובות lambda. אפשר לשמור ולהפעיל כל דבר שמגיב ל-call, בין אם מדובר ב-lambda, באובייקט מתודה או באובייקט מהמחלקה שלך:
class TextFormatter
def initialize(strategy)
@strategy = strategy
end
def format_all(words)
words.map { |w| @strategy.call(w) }.join(" ")
end
end
class Censor
def call(word)
word.size > 3 ? "*" * word.size : word
end
end
words = %w[ruby is great]
puts TextFormatter.new(->(w) { w.upcase }).format_all(words)
puts TextFormatter.new(:capitalize.to_proc).format_all(words)
puts TextFormatter.new(Censor.new).format_all(words)פלט:
RUBY IS GREAT
Ruby Is Great
**** is *****בחרו באסטרטגיה במקום בתתי־מחלקות כאשר אובייקט אחד צריך לשנות את ההתנהגות שלו בזמן שהתוכנית פועלת, או כאשר השונות היא שלב יחיד. תת־מחלקה מקבעת את ההתנהגות לכל אורך חיי האובייקט:
# ירושה ממחלקה: נקבעת בעת היצירה
ExpressShipment.new(2)
# אסטרטגיה: אפשר לשנות אותה בהמשך
shipment = Shipment.new(2, Standard.new)
shipment.strategy = Express.newאתגר
קלהשלם את אסטרטגיות המשלוח ואת ShippingCalculator. העלות של Standard#cost(kg) היא 5 ועוד 1.50 לכל ק״ג, העלות של Express#cost(kg) היא 15 ועוד 3 לכל ק״ג, והעלות של Pickup#cost(kg) היא 0. המחשבון נוצר עם אסטרטגיה, ניתן לשנות אותה באמצעות strategy=, ו-quote(kg) מחזירה 2.5 kg by Express: 22.50, תוך שימוש בשם המחלקה של האסטרטגיה.
הקוד שסופק מתחיל עם Standard וקורא פקודות כמו use express, use pickup, use standard או quote 2.5, ומדפיס כל הצעת מחיר.
הקוד שלך צריך להופיע בקבצים standard.rb, express.rb, pickup.rb ו-shipping_calculator.rb. הקובץ main.rb מכיל את קוד הקלט/פלט שסופק ואי אפשר לערוך אותו.
נסו בעצמכם
require_relative 'standard'
require_relative 'express'
require_relative 'pickup'
require_relative 'shipping_calculator'
# קוד קלט/פלט שסופק: יש להשאיר אותו כפי שהוא
input = []
while (line = gets)
input << line.chomp
end
strategies = { "standard" => Standard, "express" => Express, "pickup" => Pickup }
calc = ShippingCalculator.new(Standard.new)
input.each do |line|
cmd, arg = line.split
if cmd == "use"
calc.strategy = strategies[arg].new
else
puts calc.quote(arg.to_f)
end
end
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה תכנות מונחה עצמים
3מתודות ומשתנים של מחלקה
מתודות של מחלקהמשתני מופע של מחלקהקבועיםמתודות ליצירת מופעיםסיכום – קודי קופוןתרגלו בעצמכם: קומפיילר Ruby אונליין