תבנית האסטרטגיה
חלק מהיחידה תכנות מונחה עצמים במסלול ה-C# של Coddy. שיעור 55 מתוך 70.
תבנית האסטרטגיה היא תבנית התנהגותית שמאפשרת לך להגדיר משפחה של אלגוריתמים, לעטוף כל אחד מהם במחלקה משלו ולאפשר להחליף ביניהם בזמן ריצה. במקום לקבע את ההתנהגות בקוד, מזריקים את האסטרטגיה הרצויה לאובייקט.
התבנית מורכבת משלושה חלקים: ממשק אסטרטגיה שמגדיר את חוזה האלגוריתם, מחלקות אסטרטגיה קונקרטיות שמממשות התנהגויות שונות, ומחלקת הקשר שמשתמשת באסטרטגיה:
public interface IPaymentStrategy
{
void Pay(decimal amount);
}
public class CreditCardPayment : IPaymentStrategy
{
public void Pay(decimal amount) =>
Console.WriteLine($"Paid {amount} via Credit Card");
}
public class PayPalPayment : IPaymentStrategy
{
public void Pay(decimal amount) =>
Console.WriteLine($"Paid {amount} via PayPal");
}
public class ShoppingCart
{
private IPaymentStrategy _paymentStrategy;
public void SetPaymentMethod(IPaymentStrategy strategy)
{
_paymentStrategy = strategy;
}
public void Checkout(decimal total)
{
_paymentStrategy.Pay(total);
}
}ההקשר (ShoppingCart) לא יודע באיזו שיטת תשלום הוא משתמש — הוא פשוט קורא ל־Pay() באסטרטגיה שסופקה:
var cart = new ShoppingCart();
cart.SetPaymentMethod(new CreditCardPayment());
cart.Checkout(99.99m); // שולם 99.99 באמצעות כרטיס אשראי
cart.SetPaymentMethod(new PayPalPayment());
cart.Checkout(49.99m); // שולם 49.99 באמצעות PayPalתבנית האסטרטגיה מבטלת לוגיקה מותנית מורכבת. הוספת אמצעי תשלום חדש פירושה יצירת מחלקה חדשה שמממשת את IPaymentStrategy — אין צורך בשינויים ב־ShoppingCart. כך הקוד שלך פתוח להרחבה אך סגור לשינוי.
אתגר
קלבואו נבנה מחשבון עלויות משלוח באמצעות תבנית האסטרטגיה. לשיטות משלוח שונות יש אלגוריתמי תמחור שונים, והמערכת שלכם צריכה לאפשר מעבר ביניהן בזמן ריצה בלי לשנות את לוגיקת עיבוד ההזמנה המרכזית.
תארגנו את הקוד שלכם בשלושה קבצים:
ShippingStrategy.cs: הגדירו ממשקIShippingStrategyבמרחב השמותShipping, עם מתודהCalculateCost(double weight)שמחזירהdouble. לאחר מכן צרו שלוש מחלקות אסטרטגיה קונקרטיות:StandardShipping- מחשבת את העלות כך:weight * 1.5ExpressShipping- מחשבת את העלות כך:weight * 3.0 + 5.0(כולל עמלת משלוח מהיר קבועה)OvernightShipping- מחשבת את העלות כך:weight * 5.0 + 10.0(שירות פרימיום עם עמלת בסיס גבוהה יותר)
OrderProcessor.cs: צרו מחלקה בשםOrderProcessorבאותו מרחב שמות. זוהי מחלקת ההקשר שלכם, שמשתמשת באסטרטגיית משלוח. היא צריכה לכלול:- שדה פרטי שיחזיק את ה-
IShippingStrategyהנוכחי - מתודה
SetShippingMethod(IShippingStrategy strategy)לשינוי אסטרטגיית המשלוח - מתודה
ProcessOrder(double weight)שמשתמשת באסטרטגיה הנוכחית כדי לחשב ולהחזיר את עלות המשלוח
- שדה פרטי שיחזיק את ה-
Program.cs: חברו את כל החלקים באמצעות יצירתOrderProcessorוהדגמה של החלפת אסטרטגיות משלוח בזמן ריצה. אותו מעבד יכול לחשב עלויות באמצעות אלגוריתמים שונים, פשוט על ידי שינוי האסטרטגיה שלו.
תקבלו שתי קלטים:
- סוג שיטת המשלוח:
standard,expressאוovernight - משקל החבילה כמספר עשרוני (לדוגמה,
4.5)
צרו OrderProcessor, הגדירו את אסטרטגיית המשלוח המתאימה לפי סוג הקלט, לאחר מכן עבדו את ההזמנה והדפיסו את העלות שחושבה.
לדוגמה, אם הקלט הוא express ו-4.5, הפלט צריך להיות:
18.5הדוגמה הזו ממחישה את העוצמה של תבנית האסטרטגיה — OrderProcessor שלכם לא מכיל בעצמו שום לוגיקה לחישוב עלויות משלוח. הוא פשוט מעביר את החישוב לאסטרטגיה שסופקה לו, וכך קל להוסיף שיטות משלוח חדשות (כמו DroneDelivery) בלי לשנות כלל את המעבד!
נסו בעצמכם
using System;
using Shipping;
class Program
{
public static void Main(string[] args)
{
// קרא את הקלט
string shippingType = Console.ReadLine();
double weight = Convert.ToDouble(Console.ReadLine());
// TODO: צור מופע של OrderProcessor
// TODO: בהתאם ל-shippingType ("standard", "express" או "overnight"),
// צור את אסטרטגיית המשלוח המתאימה והגדר אותה במעבד
// TODO: עבד את ההזמנה והדפס את העלות המחושבת
}
}
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה תכנות מונחה עצמים
1יסודות התכנות מונחה העצמים
קבצים חיצונייםמרחבי שמות והנחיותמבוא למחלקות ולאובייקטיםמילת המפתח 'this'מתודות ופרמטריםשדות לעומת מאפייניםבנאיםאתחול אובייקטיםסיכום – מחשבון פשוט4ירושה
תחביר ירושה בסיסית (:)מילת המפתח 'base'מילות המפתח Virtual ו-Overrideמחלקות Sealedמחלקת הבסיס 'object'סיכום – היררכיית עובדים7תכונות מתקדמות
העמסת אופרטוריםאינדקסרים (this[])דריסת ToString()מתודות הרחבהסיכום – רשימה מותאמת אישית10תבניות עיצוב חלק 1
מבוא לתבניות עיצובSingleton בטוח לריבוי תהליכוניםתבנית המפעלתבנית הצופה (אירועים)תבנית האסטרטגיה2מאפיינים וחברים סטטיים
מאפיינים במימוש אוטומטימאפיינים לקריאה בלבד ולכתיבה בלבדשדות ומתודות סטטייםמחלקות סטטיותחברים עם גוף ביטוי5פולימורפיזם וממשקים
פולימורפיזם בזמן קומפילציה לעומת בזמן ריצהממשק לעומת מחלקה מופשטתממשקים מרוביםממשקים מפורשיםהמרה כלפי מעלה והמרה כלפי מטהחזרה: מחשבון צורות8מושגים מתקדמים בתכנות מונחה עצמים
קומפוזיציה במקום ירושהGenerics (מחלקות ומתודות)נציגים ואירועיםמאפיינים ורפלקציהIDisposable והצהרת usingיסודות הזרקת תלויותתרגלו בעצמכם: קומפיילר C# אונליין