Menu
Coddy logo textTech

תבנית הפקודה

חלק מהיחידה תכנות מונחה עצמים במסלול ה-Java של Coddy. שיעור 70 מתוך 87.

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

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

Command שמצהיר על המתודה execute, מחלקות ConcreteCommand שמממשות פעולות ספציפיות, Receiver שמבצע את העבודה בפועל, ו-Invoker שמפעיל פקודות:

interface Command {
    void execute();
}
class Light {  // מקבל
    public void turnOn() {
        System.out.println("Light is ON");
    }
    public void turnOff() {
        System.out.println("Light is OFF");
    }
}
class LightOnCommand implements Command {
    private Light light;
    
    public LightOnCommand(Light light) {
        this.light = light;
    }
    
    public void execute() {
        light.turnOn();
    }
}
class RemoteControl {  // מפעיל
    private Command command;
    
    public void setCommand(Command command) {
        this.command = command;
    }
    
    public void pressButton() {
        command.execute();
    }
}

המפעיל לא יודע איזו פעולה תבוצע. הוא פשוט קורא ל־execute():

Light light = new Light();
Command lightOn = new LightOnCommand(light);

RemoteControl remote = new RemoteControl();
remote.setCommand(lightOn);
remote.pressButton();  // פלט: האור דולק

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

challenge icon

אתגר

קל

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

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

  • Command.java: הגדירו את הממשק Command, שכל פקודות המכשירים יממשו. עליו להצהיר על מתודה יחידה execute(), שמבצעת את פעולת הפקודה.
  • Devices.java: צרו שתי מחלקות מקבלות שמייצגות מכשירים לבית חכם:

    Television - יש לה מתודות powerOn() שמדפיסה TV is now ON, powerOff() שמדפיסה TV is now OFF, ו-setChannel(int channel) שמדפיסה TV channel set to [channel].

    Thermostat - יש לה מתודות setTemperature(int temp) שמדפיסה Thermostat set to [temp] degrees, ו-turnOff() שמדפיסה Thermostat turned OFF.

  • Commands.java: צרו מחלקות פקודה קונקרטיות שעוטפות פעולות של מכשירים:

    TVOnCommand - מקבלת Television בבנאי שלה וקוראת ל-powerOn() בעת ביצוע הפקודה.

    TVOffCommand - מקבלת Television בבנאי שלה וקוראת ל-powerOff() בעת ביצוע הפקודה.

    TVChannelCommand - מקבלת Television ואת int channel בבנאי שלה, וקוראת ל-setChannel() עם הערוץ הזה בעת ביצוע הפקודה.

    ThermostatSetCommand - מקבלת Thermostat ואת int temperature בבנאי שלה, וקוראת ל-setTemperature() עם הערך הזה בעת ביצוע הפקודה.

  • Main.java: צרו מחלקה בשם RemoteControl (המפעיל), שיש לה מתודה setCommand(Command cmd) לשמירת פקודה ומתודה pressButton() לביצוע הפקודה השמורה.

    במתודה הראשית שלכם תקבלו שני קלטים: מספר ערוץ טלוויזיה (מספר שלם) וטמפרטורה לתרמוסטט (מספר שלם).

    צרו Television ו-Thermostat. צרו RemoteControl והדגימו את תבנית הפקודה כך:

    1. הגדירו TVOnCommand ולחצו על הכפתור
    2. הגדירו TVChannelCommand עם ערוץ הטלוויזיה שהתקבל בקלט ולחצו על הכפתור
    3. הגדירו ThermostatSetCommand עם הטמפרטורה שהתקבלה בקלט ולחצו על הכפתור
    4. הגדירו TVOffCommand ולחצו על הכפתור

תקבלו שני קלטים לפי הסדר: ערוץ הטלוויזיה (מספר שלם) וטמפרטורת התרמוסטט (מספר שלם).

לדוגמה, עבור הקלטים 5 ו-72, הפלט שלכם יהיה:

TV is now ON
TV channel set to 5
Thermostat set to 72 degrees
TV is now OFF

שימו לב ש-RemoteControl אף פעם לא מתקשר ישירות עם המכשירים. הוא מכיר רק את הממשק Command. כל פקודה עוטפת את כל מה שנדרש לביצוע הפעולה שלה, וכך קל להוסיף מכשירים ופקודות חדשים בלי לשנות את המפעיל!

נסו בעצמכם

import java.util.Scanner;

// TODO: צרו את המחלקה RemoteControl (מפעילת הפקודות) עם:
// - מתודה setCommand(Command cmd) לשמירת פקודה
// - מתודה pressButton() לביצוע הפקודה שנשמרה

class RemoteControl {
    // TODO: ממשו את RemoteControl
}

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // קראו את הקלט
        int channel = scanner.nextInt();
        int temperature = scanner.nextInt();
        
        // TODO: צרו Television ו-Thermostat
        
        // TODO: צרו RemoteControl
        
        // TODO: הדגימו את תבנית הפקודה:
        // 1. הגדירו TVOnCommand ולחצו על הכפתור
        // 2. הגדירו TVChannelCommand עם הערוץ מהקלט ולחצו על הכפתור
        // 3. הגדירו ThermostatSetCommand עם הטמפרטורה מהקלט ולחצו על הכפתור
        // 4. הגדירו TVOffCommand ולחצו על הכפתור
        
        scanner.close();
    }
}
quiz iconבחנו את עצמכם

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

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

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