الأمر بسيط جداً صديقي عثمان.’
هذا اسمه decorator design pattern, يعني نمط التنميق بالعربي
نفترض أن عندك اثنين دوال function مثلاً:
def say_hello():
print('hello')
def say_hi():
print('hi')
وأنت تريد طباعة جملة ثانية داخل هذه الدالتين:
def say_hello():
print('Printing........')
print('hello')
def say_hi():
print('Printing........')
print('hi')
لكن هذا يخرق اثنين مبادئ principles:
- مبدأ DRY - Dont Repeat Yourself الذي يقول:
التكرار سيء… استعملنا نفس السطر print('printing')
مرتين, ولازمنا نعدل عليه مرتين في المستقبل لو أردنا التعديل عليه.
- مبدأ Open-Closed الذي يقول:
الكود يجب أن مفتوح للإضافات Open… لكن مغلق للتعديلات Closed
يعني بدون ما تعدل الدالة أنت تريد تضيف عليها شيء.
لكن كيف ؟
هنا يأتي decorator يحل لنا المشكلة
تكتب فقط:
def printer(my_func):
def wrapper():
print('Printing........')
my_func()
return wrapper
فكرته أنه تدخل عليه دالة مكان my_func, وهو يقوم بتشغيلها, لكن قبلها يقوم بالذي نريد.
يعني أول شيء print('Printing........')
وبعدين يستدعي الدالة التي تدخل عليه my_func
بهذا الشكل:
def printer(my_func):
def wrapper():
print('Printing........')
my_func()
return wrapper
def say_hello():
print('hello')
say_hello = printer(say_hello)
say_hello()
هكذا هو يمرر الدالة say_hello على الدالة printer, ثم يستدعيها.
شكل الكود قبيح نوعاً ما… صح ؟
لدى بايثون طريقة أجمل بهذا الشكل:
@printer
def say_hello():
print('hello')
say_hello()
النتيجة النهائية:
def printer(my_func):
def wrapper():
print('Printing........')
my_func()
return wrapper
@printer
def say_hello():
print('hello')
@printer
def say_hi():
print('hi')
say_hello()
say_hi()
لاحظ الآن بدون خرق Open-Closed principle و Dont Repeat Yourself أصبح بإمكاننا إضافة أكواد على الدوال بدون التعديل عليها.