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

نمط الحالة

جزء من قسم Object Oriented Programming في رحلة Python على Coddy — الدرس 53 من 64.

يسمح نمط الحالة (State Pattern) للكائن بتغيير سلوكه عندما تتغير حالته الداخلية. يبدو الكائن وكأنه يغير فئته (class) بناءً على حالته الحالية.

إليك فئات حالة بسيطة لإشارة مرور:

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"

تحدد كل حالة ما يحدث عند الانتقال إلى الحالة التالية.

أنشئ فئة سياق (context class) تحتفظ بالحالة الحالية:

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 Pattern) بتغليف السلوك الخاص بالحالة في فئات منفصلة ويسمح لكائن السياق (context object) بالتفويض إلى الحالة الحالية. عندما تتغير الحالة، يتغير السلوك تلقائيًا. هذا يلغي جمل if/else المعقدة ويجعل إضافة حالات جديدة أسهل.

challenge icon

التحدي

سهل

في هذا التحدي، ستقوم بتنفيذ فئة State في state.py مع التغليف والأساليب المناسبة. يحتوي الملف على تعليقات TODO مفصلة لإرشادك في التنفيذ خطوة بخطوة.

تم تصميم مجموعة الاختبارات للتحقق من أن تنفيذك يلبي جميع المتطلبات ويتعامل مع الحالات الاستثنائية بشكل صحيح. استخدم نتائج الاختبار لفهم السلوك المتوقع وتحسين الحل الخاص بك.

ورقة مرجعية

يسمح نمط الحالة (State Pattern) للكائن بتغيير سلوكه عندما تتغير حالته الداخلية. يبدو أن الكائن يغير فئته بناءً على حالته الحالية.

قم بإنشاء فئات الحالة التي تحدد السلوك لكل حالة:

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"

قم بإنشاء فئة سياق (context class) تحتفظ بالحالة الحالية:

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()}")  # الحالي: Red
light.change()  # Red -> Green
print(f"Current: {light.get_color()}")  # الحالي: Green

يقوم نمط الحالة بتغليف السلوك الخاص بكل حالة في فئات منفصلة ويسمح لكائن السياق بالتفويض إلى الحالة الحالية. هذا يلغي جمل if/else المعقدة ويجعل إضافة حالات جديدة أسهل.

جرّب بنفسك

from state import State

# معالج حالات الاختبار الشامل
test_case = input()

if test_case == "basic_test":
    obj = State("Test Name")
    obj.display_info()

elif test_case == "validation_test":
    obj = State("Validation Test")
    print(f"Name: {obj.name}")

elif test_case == "empty_name_test":
    obj = State("")
    obj.display_info()
    print(f"Name property: {obj.name}")

elif test_case == "special_chars_test":
    obj = State("Test@#$%")
    obj.display_info()
    print(f"Name property: {obj.name}")

elif test_case == "long_name_test":
    long_name = "A" * 100
    obj = State(long_name)
    obj.display_info()
    print(f"Name length: {len(obj.name)}")

elif test_case == "multiple_states_test":
    states = [
        State("California"),
        State("Texas"),
        State("New York"),
        State("Florida")
    ]
    
    for state in states:
        state.display_info()
        print(f"Name via property: {state.name}")

elif test_case == "attribute_access_test":
    obj = State("Access Test")
    # الوصول المباشر إلى السمة الخاصة (غير مستحسن)
    print(f"Direct access (not recommended): {obj._name}")
    # الوصول عبر الخاصية (مستحسن)
    print(f"Property access (recommended): {obj.name}")

elif test_case == "property_behavior_test":
    obj = State("Original Name")
    print(f"Original name: {obj.name}")
    
    # محاولة تعديل الاسم (سيفشل لعدم وجود دالة تعيين setter)
    try:
        obj.name = "New Name"
    except AttributeError as e:
        print(f"Error when trying to modify name: {e}")
    
    # إظهار أن الاسم لم يتغير
    print(f"Name after modification attempt: {obj.name}")
quiz iconاختبر نفسك

يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.

جميع دروس Object Oriented Programming