Menu
Coddy logo textTech

תבנית 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
challenge icon

אתגר

קל

השלם את אסטרטגיות המשלוח ואת 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
quiz iconבחנו את עצמכם

השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.

כל השיעורים ביחידה תכנות מונחה עצמים

תרגלו בעצמכם: קומפיילר Ruby אונליין