نمط الأمر
جزء من قسم البرمجة كائنية التوجه في رحلة Python على Coddy. الدرس 49 من 64.
يغلّف نمط Command الطلب في كائن، مما يتيح لك وضع العمليات في قائمة انتظار، وتسجيل الطلبات، ودعم وظيفة التراجع. ويفصل بين الكائن الذي يستدعي العملية والكائن الذي ينفّذها.
إليك أصناف command بسيطة:
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")أنشئ مستدعيًا ينفّذ الأوامر:
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()
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 الطلبات إلى كائنات يمكن تخزينها وتمريرها وتنفيذها لاحقًا. لا يحتاج invoker إلى معرفة كيفية تنفيذ العملية - بل يستدعي execute() على كائن command. يتيح ذلك ميزات مثل التراجع/الإعادة، ووضع العمليات في قائمة انتظار، وتسجيل أوامر command.
التحدي
سهلفي هذا التحدي، ستنفّذ الفئة الأساسية التأسيسية Command في command.py: وهي لبنة البناء الأساسية لنمط Command. يركّز هذا التمرين تحديدًا على التغليف: تخزين البيانات بشكل خاص وإتاحة الوصول إليها بأمان من خلال خاصية.
عدّل command.py فقط وفقًا لتعليقات TODO. سترشدك تعليقات TODO إلى ما يلي:
- تخزين اسم الأمر كسمة خاصة (
_name) - إتاحته عبر خاصية للقراءة فقط (
name) - تنفيذ أسلوب
display_info()يطبع اسم الأمر
ملاحظة: يغطي هذا التحدي الفئة الأساسية Command فقط: أما Invoker وReceiver ووظيفة undo فسيتم تقديمها في دروس لاحقة. يمنحك إكمال هذه الخطوة أساس التغليف الذي يُبنى عليه النمط الكامل.
سيختبر driver.py تنفيذك، ويتحقق من:
- الوظائف الأساسية وتنسيق المخرجات
- الحالات الحدّية (المدخلات الفارغة، والأحرف الخاصة، والأسماء الطويلة)
- حماية الخاصية للقراءة فقط (محاولة
obj.name = ...يجب أن ترفعAttributeError) - وجود السمة الخاصة
_name
جرّب بنفسك
# استيراد الفئة 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:
# يجب أن يفشل هذا لأن name خاصية للقراءة فقط
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)}")يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس البرمجة كائنية التوجه
1أساسيات OOP
الملفات الخارجيةمقدمة في OOPClasses مقابل Objectsمعامل selfMethodsAttributesدالة البناء (__init__)مراجعة - آلة حاسبة بسيطة4الوراثة
الوراثة الأساسيةدالة ()superإعادة تعريف الدوال (Method Overriding)الوراثة المتعددةترتيب استدعاء الدوال (Method Resolution Order)مراجعة - هيكلية الموظفين5تعدد الأشكال
مراجعة إعادة تعريف الدوالمفهوم Duck Typingالأصناف والدوال المجردةتصميم الواجهاتملخص - حاسبة الأشكالتدرّب بنفسك: مترجم Python عبر الإنترنت