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

نمط الأمر

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

يقوم نمط الأمر (Command Pattern) بتغليف الطلب ككائن، مما يسمح لك بوضع العمليات في طابور، وتسجيل الطلبات، ودعم وظيفة التراجع. كما أنه يفصل بين الكائن الذي يستدعي العملية والكائن الذي يقوم بتنفيذها.

فيما يلي أصناف الأوامر البسيطة:

class Command:
    def execute(self):
        pass

class LightOnCommand(Command):
    def __init__(self, light):
        self.light = light
    
    def execute(self):
        self.light.turn_on()

class LightOffCommand(Command):
    def __init__(self, light):
        self.light = light
    
    def execute(self):
        self.light.turn_off()

كل أمر يغلف عملية محددة على كائن مستلم.

أنشئ المستقبل (receiver) الذي يقوم بالعمل الفعلي:

class Light:
    def turn_on(self):
        print("Light is on")
    
    def turn_off(self):
        print("Light is off")

قم بإنشاء مستدعي (invoker) يقوم بتنفيذ الأوامر:

class RemoteControl:
    def __init__(self):
        self.command = None
    
    def set_command(self, command):
        self.command = command
    
    def press_button(self):
        self.command.execute()

استخدم نمط الأمر (command pattern):

# إنشاء المستقبل (receiver)
light = Light()

# إنشاء الأوامر
light_on = LightOnCommand(light)
light_off = LightOffCommand(light)

# إنشاء المستدعي (invoker)
remote = RemoteControl()

# تنفيذ أوامر مختلفة
remote.set_command(light_on)
remote.press_button()

remote.set_command(light_off)
remote.press_button()

إضافة دعم لعمليات التراجع:

class UndoableCommand(Command):
    def undo(self):
        pass

class LightOnCommand(UndoableCommand):
    def __init__(self, light):
        self.light = light
    
    def execute(self):
        self.light.turn_on()
    
    def undo(self):
        self.light.turn_off()

class SmartRemote:
    def __init__(self):
        self.last_command = None
    
    def execute_command(self, command):
        command.execute()
        self.last_command = command
    
    def undo(self):
        if self.last_command:
            self.last_command.undo()

smart_remote = SmartRemote()
smart_remote.execute_command(LightOnCommand(light))
smart_remote.undo()  # يطفئ الضوء

الناتج:

Light is on
Light is off
Light is on
Light is off

نقطة رئيسية: يحول نمط الأمر (Command Pattern) الطلبات إلى كائنات يمكن تخزينها، وتمريرها، وتنفيذها لاحقاً. لا يحتاج المستدعي (invoker) إلى معرفة كيفية تنفيذ العملية - فهو يكتفي باستدعاء execute() على كائن الأمر. يتيح ذلك ميزات مثل التراجع/الإعادة، وجدولة العمليات، وتسجيل الأوامر.

challenge icon

التحدي

سهل

في هذا التحدي، ستقوم بتنفيذ الفئة الأساسية Command في ملف command.py — وهي اللبنة الأساسية لنمط الأمر (Command Pattern). يركز هذا التمرين بشكل خاص على التغليف (encapsulation): تخزين البيانات بشكل خاص (private) وعرضها بأمان من خلال خاصية (property).

قم فقط بتعديل command.py وفقاً لتعليقات TODO. ستوجهك تعليقات TODO إلى:

  • تخزين اسم الأمر كـ سمة خاصة (_name)
  • عرضها عبر خاصية للقراءة فقط (name)
  • تنفيذ تابع display_info() الذي يطبع اسم الأمر

ملاحظة: يغطي هذا التحدي فئة Command الأساسية فقط — سيتم تقديم وظائف Invoker و Receiver و undo في دروس لاحقة. إكمال هذه الخطوة يمنحك أساس التغليف الذي يبنى عليه النمط الكامل.

سيتم اختبار تنفيذك بواسطة driver.py، والذي يتحقق من:

  • الوظائف الأساسية وتنسيق المخرجات
  • الحالات الحدية (المدخلات الفارغة، الرموز الخاصة، الأسماء الطويلة)
  • حماية خاصية القراءة فقط (محاولة تنفيذ obj.name = ... يجب أن تثير AttributeError)
  • وجود السمة الخاصة _name

ورقة مرجعية

يقوم نمط الأمر (Command Pattern) بتغليف الطلب ككائن، مما يسمح لك بوضع العمليات في قائمة انتظار، وتسجيل الطلبات، ودعم وظيفة التراجع.

الهيكل الأساسي للأمر:

class Command:
    def execute(self):
        pass

class LightOnCommand(Command):
    def __init__(self, light):
        self.light = light
    
    def execute(self):
        self.light.turn_on()

class LightOffCommand(Command):
    def __init__(self, light):
        self.light = light
    
    def execute(self):
        self.light.turn_off()

إنشاء مستقبل (receiver) يقوم بالعمل الفعلي:

class Light:
    def turn_on(self):
        print("Light is on")
    
    def turn_off(self):
        print("Light is off")

إنشاء مستدعي (invoker) يقوم بتنفيذ الأوامر:

class RemoteControl:
    def __init__(self):
        self.command = None
    
    def set_command(self, command):
        self.command = command
    
    def press_button(self):
        self.command.execute()

مثال على الاستخدام:

# إنشاء المستقبل
light = Light()

# إنشاء الأوامر
light_on = LightOnCommand(light)
light_off = LightOffCommand(light)

# إنشاء المستدعي
remote = RemoteControl()

# تنفيذ أوامر مختلفة
remote.set_command(light_on)
remote.press_button()

remote.set_command(light_off)
remote.press_button()

إضافة وظيفة التراجع:

class UndoableCommand(Command):
    def undo(self):
        pass

class LightOnCommand(UndoableCommand):
    def __init__(self, light):
        self.light = light
    
    def execute(self):
        self.light.turn_on()
    
    def undo(self):
        self.light.turn_off()

class SmartRemote:
    def __init__(self):
        self.last_command = None
    
    def execute_command(self, command):
        command.execute()
        self.last_command = command
    
    def undo(self):
        if self.last_command:
            self.last_command.undo()

جرّب بنفسك

# استيراد فئة Command من ملف command.py
from command import Command

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

if test_case == "basic_test":
    obj = Command("Test Name")
    obj.display_info()
elif test_case == "validation_test":
    obj = Command("Validation Test")
    print(f"Name: {obj.name}")
elif test_case == "empty_name_test":
    obj = Command("")
    obj.display_info()
    print(f"Empty name handled: {'Yes' if obj.name == '' else 'No'}")
elif test_case == "property_access_test":
    obj = Command("Property Test")
    original_name = obj.name
    try:
        # يجب أن يفشل هذا لأن الاسم خاصية للقراءة فقط
        obj.name = "Modified Name"
        print("Property protection failed")
    except AttributeError:
        print("Property protected successfully")
    print(f"Name unchanged: {obj.name == original_name}")
elif test_case == "multiple_commands_test":
    commands = [
        Command("First Command"),
        Command("Second Command"),
        Command("Third Command")
    ]
    for cmd in commands:
        cmd.display_info()
elif test_case == "attribute_test":
    obj = Command("Attribute Test")
    has_private_name = hasattr(obj, "_name")
    print(f"Has _name attribute: {has_private_name}")
elif test_case == "special_chars_test":
    obj = Command("!@#$%^&*()_+{}[]|\\:;\"'<>,.?/")
    obj.display_info()
elif test_case == "long_name_test":
    long_name = "A" * 100
    obj = Command(long_name)
    obj.display_info()
    print(f"Name length: {len(obj.name)}")
quiz iconاختبر نفسك

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

جميع دروس Object Oriented Programming