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

نمط الحالة

جزء من قسم البرمجة كائنية التوجه في رحلة 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

النقطة الأساسية: يُغلّف نمط الحالة السلوك الخاص بكل حالة في فئات منفصلة، ويتيح لكائن السياق تفويض المهام إلى الحالة الحالية. عند تغيّر الحالة، يتغيّر السلوك تلقائيًا. وهذا يلغي عبارات 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 عبر الإنترنت