Menu
Coddy logo textTech

תבנית Strategy

חלק מהיחידה תכנות מונחה עצמים במסלול ה-PHP של Coddy. שיעור 74 מתוך 91.

תבנית האסטרטגיה היא תבנית עיצוב התנהגותית שמאפשרת להגדיר משפחה של אלגוריתמים, לעטוף כל אחד מהם במחלקה משלו ולאפשר להחליף ביניהם בזמן ריצה. האובייקט שמשתמש באסטרטגיה אינו צריך לדעת איזה אלגוריתם הוא מריץ.

דמיינו עגלת קניות שיכולה להחיל אסטרטגיות הנחה שונות. במקום לקבע את לוגיקת ההנחה בקוד באמצעות תנאים, מגדירים כל הנחה כמחלקה נפרדת:

<?php
interface DiscountStrategy {
    public function calculate(float $total): float;
}

class NoDiscount implements DiscountStrategy {
    public function calculate(float $total): float {
        return $total;
    }
}

class PercentageDiscount implements DiscountStrategy {
    public function __construct(private int $percent) {}
    
    public function calculate(float $total): float {
        return $total - ($total * $this->percent / 100);
    }
}

class FixedDiscount implements DiscountStrategy {
    public function __construct(private float $amount) {}
    
    public function calculate(float $total): float {
        return max(0, $total - $this->amount);
    }
}

מחלקת ההקשר מקבלת כל אסטרטגיה ומאצילה לה את החישוב:

<?php
class ShoppingCart {
    public function __construct(private DiscountStrategy $discount) {}
    
    public function setDiscount(DiscountStrategy $discount): void {
        $this->discount = $discount;
    }
    
    public function checkout(float $total): float {
        return $this->discount->calculate($total);
    }
}

$cart = new ShoppingCart(new NoDiscount());
echo $cart->checkout(100) . "\n";

$cart->setDiscount(new PercentageDiscount(20));
echo $cart->checkout(100);

פלט:

100
80

תבנית האסטרטגיה מצטיינת כשיש לך כמה דרכים לבצע פעולה ואתה רוצה לעבור ביניהן בלי לשנות את המחלקה שמשתמשת בהן. הוספת סוג הנחה חדש פירושה יצירת מחלקה חדשה, בלי לגעת בקוד הקיים.

challenge icon

אתגר

קל

בואו נבנה מחשבון עלויות משלוח באמצעות תבנית האסטרטגיה (Strategy Pattern). לשיטות משלוח שונות יש כללי תמחור שונים: משלוח רגיל גובה תעריף קבוע, משלוח אקספרס מוסיף אחוז, ומשלוח לילה משלב בין השניים. תבנית האסטרטגיה מאפשרת להחליף בין החישובים האלה בלי לשנות את הקוד שמשתמש בהם.

תארגנו את הקוד בארבעה קבצים:

  • ShippingStrategy.php: צרו ממשק ShippingStrategy שמגדיר את החוזה עבור כל שיטות המשלוח. צריכה להיות בו מתודה calculate(float $weight): float שמקבלת את משקל החבילה ומחזירה את עלות המשלוח.
  • ShippingMethods.php: כללו את קובץ ShippingStrategy וצרו שלוש מחלקות שמממשות את הממשק:
    • StandardShipping: גובה תעריף קבוע של $5.00 ללא קשר למשקל
    • ExpressShipping: גובה $2.00 לכל קילוגרם (הכפילו את המשקל ב-2)
    • OvernightShipping: גובה עמלת בסיס של $10.00 ועוד $3.00 לכל קילוגרם
  • ShippingCalculator.php: כללו את קובץ ShippingStrategy וצרו מחלקה ShippingCalculator שמשמשת כהקשר. המחשבון שלכם צריך:
    • לקבל ShippingStrategy בבנאי שלו (השתמשו בקידום מאפיינים בבנאי)
    • להכיל מתודה setStrategy(ShippingStrategy $strategy): void לשינוי שיטת המשלוח בזמן הריצה
    • להכיל מתודה calculateCost(float $weight): float שמעבירה את החישוב לאסטרטגיה הנוכחית
  • main.php: כללו את הקבצים ShippingMethods ו-ShippingCalculator. תקבלו שתי כניסות: סוג משלוח ("standard", "express" או "overnight") ומשקל חבילה.

    צרו ShippingCalculator שמתחיל עם StandardShipping. בהתאם לקלט של סוג המשלוח, השתמשו ב-setStrategy() כדי לעבור לשיטת המשלוח המתאימה. לאחר מכן חשבו את העלות עבור המשקל הנתון והדפיסו את התוצאה בפורמט של שתי ספרות אחרי הנקודה העשרונית.

    הפלט צריך להיות: Shipping cost: $[cost]

האתגר הזה מדגים כיצד תבנית האסטרטגיה הופכת את מערכת המשלוחים שלכם לגמישה: הוספת שיטת משלוח חדשה, כמו SameDayShipping, דורשת רק יצירת מחלקה חדשה שמממשת את הממשק, בלי לגעת במחשבון או בשיטות המשלוח הקיימות.

נסו בעצמכם

<?php
require_once 'ShippingMethods.php';
require_once 'ShippingCalculator.php';

// קרא את הקלט
$shippingType = trim(fgets(STDIN));
$weight = floatval(fgets(STDIN));

// TODO: צור ShippingCalculator שמתחיל עם StandardShipping

// TODO: בהתאם לקלט של סוג המשלוח ("standard", "express" או "overnight"),
// השתמש ב-setStrategy() כדי לעבור לשיטת המשלוח המתאימה

// TODO: חשב את העלות עבור המשקל הנתון

// TODO: הדפס את התוצאה בפורמט של שתי ספרות אחרי הנקודה העשרונית
// פורמט הפלט: Shipping cost: $[cost]

?>
quiz iconבחנו את עצמכם

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

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

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