Menu
Coddy logo textTech

תבנית המצב

חלק מהיחידה תכנות מונחה עצמים במסלול ה-Python של Coddy. שיעור 53 מתוך 64.

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

הנה מחלקות מצב פשוטות עבור רמזור:

class RedState:
    def next_state(self, light):
        print("Red -> Green")
        light.state = GreenState()
    
    def current_color(self):
        return "Red"

class GreenState:
    def next_state(self, light):
        print("Green -> Yellow")
        light.state = YellowState()
    
    def current_color(self):
        return "Green"

class YellowState:
    def next_state(self, light):
        print("Yellow -> Red")
        light.state = RedState()
    
    def current_color(self):
        return "Yellow"

כל מצב מגדיר מה קורה בעת מעבר למצב הבא.

צרו מחלקת הקשר שמחזיקה את המצב הנוכחי:

class TrafficLight:
    def __init__(self):
        self.state = RedState()  # מתחילים באדום
    
    def change(self):
        self.state.next_state(self)
    
    def get_color(self):
        return self.state.current_color()

הרמזור מאציל את ההתנהגות לאובייקט המצב הנוכחי שלו.

השתמשו ברמזור:

light = TrafficLight()
print(f"Current: {light.get_color()}")

light.change()  # אדום -> ירוק
print(f"Current: {light.get_color()}")

light.change()  # ירוק -> צהוב
print(f"Current: {light.get_color()}")

light.change()  # צהוב -> אדום
print(f"Current: {light.get_color()}")

צרו דוגמה נוספת עם נגן פשוט:

class PlayingState:
    def play(self, player):
        print("Already playing")
    
    def stop(self, player):
        print("Stopping music")
        player.state = StoppedState()

class StoppedState:
    def play(self, player):
        print("Starting music")
        player.state = PlayingState()
    
    def stop(self, player):
        print("Already stopped")

class MusicPlayer:
    def __init__(self):
        self.state = StoppedState()
    
    def play(self):
        self.state.play(self)
    
    def stop(self):
        self.state.stop(self)

player = MusicPlayer()
player.play()   # מתחיל לנגן מוזיקה
player.play()   # כבר מנגן
player.stop()   # מפסיק לנגן מוזיקה
player.stop()   # הניגון כבר הופסק

פלט:

Current: Red
Red -> Green
Current: Green
Green -> Yellow
Current: Yellow
Yellow -> Red
Current: Red
Starting music
Already playing
Stopping music
Already stopped

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

challenge icon

אתגר

קל

ממשו את תבנית State בקובץ state.py עבור מנורה עם כפתור אחד. כל לחיצה מעבירה את המנורה בין שלושה מצבים במחזור: כבויה, עוצמה נמוכה, עוצמה גבוהה, וחזרה למצב כבוי. במקום שרשרת של if על מחרוזת, כל מצב הוא אובייקט בפני עצמו שיודע מה קורה כשלוחצים על הכפתור.

  • LampState היא מחלקת הבסיס עם press(lamp) ו-describe().
  • OffState, LowState ו-HighState מממשות אותן: press קוראת ל-lamp.set_state(...) עם המצב הבא (מכבוי לעוצמה נמוכה, מעוצמה נמוכה לעוצמה גבוהה, ומעוצמה גבוהה לכבוי), ו-describe מחזירה Lamp is off, Lamp is on low או Lamp is on high.
  • Lamp היא ההקשר: היא מתחילה במצב OffState, המתודה set_state מחליפה את אובייקט המצב, המתודה press_button מעבירה את הפעולה למצב הנוכחי, והמתודה status מחזירה את התיאור הנוכחי.

הקובץ driver.py נעול: הוא לוחץ על הכפתור ומדפיס את המצב. שימו לב ש-Lamp אף פעם לא בודקת באיזה מצב היא נמצאת; אובייקטי המצב הם שמחליטים.

נסו בעצמכם

from state import Lamp

# מטפל במקרי בדיקה (אין לשנות)
test_case = input()
lamp = Lamp()

if test_case == "initial_test":
    print(lamp.status())
elif test_case == "one_press_test":
    lamp.press_button()
    print(lamp.status())
elif test_case == "cycle_test":
    for _ in range(4):
        print(lamp.status())
        lamp.press_button()
elif test_case == "many_presses_test":
    for _ in range(7):
        lamp.press_button()
    print(lamp.status())
quiz iconבחנו את עצמכם

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

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

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