Menu
Coddy logo textTech
flag Ar iconالعربيةdown icon

نمط 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 عبر الإنترنت