از طریق منوی جستجو مطلب مورد نظر خود در وبلاگ را به سرعت پیدا کنید
الگوهای طراحی اختصاصی پایتون
سرفصلهای مطلب
معرفی
تا به حال، ما الگوهای طراحی خلاقانه، ساختاری و رفتاری را پوشش داده ایم. این ستونهای بنیادی بینشهایی را درباره ایجاد برنامههای کاربردی پایتون زیبا، قابل نگهداری و مقیاسپذیر ارائه کردهاند. با این حال، همانطور که ما عمیقتر به تفاوتهای ظریف پایتون میپردازیم، برخی از الگوهای طراحی ظاهر میشوند که منحصر به خود زبان هستند – الگوهای طراحی اختصاصی پایتون.
نحو بیانی و ماهیت پویای پایتون منجر به تولد الگوهای خاصی شده است که ممکن است در سایر زبان های برنامه نویسی رایج یا حتی وجود نداشته باشند. این الگوها با چالشهای خاص توسعه پایتون مقابله میکنند و به توسعهدهندگان راه پایتونیکتری برای حل مشکلات ارائه میدهند.
در این مقاله نهایی از سری الگوهای طراحی خود، به الگوهای زیر می پردازیم:
الگوی شی جهانی
هنگام توسعه برنامهها، بهویژه برنامههایی که پیچیدگی قابلتوجهی دارند، اغلب خود را در سناریوهایی مییابیم که در آن نیاز داریم به اشتراک گذاشتن وضعیت یک شی در بخش های مختلف سیستم. در حالی که متغیرهای سراسری می توانند این هدف را برآورده کنند، به دلیل پیچیدگی ها و غیرقابل پیش بینی بودن که می توانند معرفی کنند، عموماً مورد بی مهری قرار می گیرند.
در عوض، الگوی شی جهانی یک راه حل کنترل شده و ظریف تر برای این معضل ارائه می دهد. در هسته خود، این الگو با هدف ارائه یک نمونه مشترک منحصر به فرد از یک شی در کل برنامه، تضمین می کند که حالت سازگار و هماهنگ باقی می ماند.
تصور کنید در حال طراحی یک سیستم ورود به سیستم برای یک برنامه هستید. حفظ پیکربندی های ثابت (مانند سطوح گزارش یا فرمت های خروجی) در ماژول ها و اجزای مختلف برای لاگر بسیار مهم است. به جای ایجاد نمونههای لاگر جدید یا انتقال لاگر به اطراف، داشتن یک نمونه ثبتکننده واحد و در دسترس جهانی که پیکربندیهای مشترک را حفظ میکند، سودمند خواهد بود.
الگوی شیء جهانی معمولاً از اهرم استفاده می کند الگوی تک تن (که قبلا در این درس توضیح دادیم) برای اطمینان از اینکه یک کلاس فقط یک نمونه دارد و یک نقطه جهانی برای دسترسی به آن فراهم می کند. مزیت اصلی استفاده از این الگو این است کنترل و پیش بینی پذیری ارائه می دهد. تغییرات ایجاد شده در شی سراسری از یک ماژول در بقیه ماژول ها منعکس می شود و رفتار هماهنگ را تضمین می کند.
بیایید با استفاده از الگوی Global Object، Logger جهانی را از مثال خود ایجاد کنیم:
class GlobalLogger:
_instance = None
def __new__(cls, *args, **kwargs):
if not cls._instance:
cls._instance = super(GlobalLogger, cls).__new__(cls, *args, **kwargs)
return cls._instance
def __init__(self):
self.log_level = "INFO"
def set_log_level(self, level):
self.log_level = level
def log(self, message):
print(f"({self.log_level}) - {message}")
اینجا، GlobalLogger
همیشه همان نمونه را برمی گرداند و اطمینان حاصل می کند که وضعیت پیکربندی در سراسر برنامه سازگار است:
logger1 = GlobalLogger()
logger1.log("This is an info message.")
logger2 = GlobalLogger()
logger2.set_log_level("ERROR")
logger2.log("This is an error message.")
logger1.log("This message also shows as an error.") # The log level has been globally updated
این به ما می دهد:
(INFO) - This is an info message.
(ERROR) - This is an error message.
(ERROR) - This message also shows as an error.
الگوی روش Prebound
یکی از جنبههای جذاب ماهیت پویای پایتون، توانایی آن است ایجاد و دستکاری توابع و متدها در زمان اجرا. اغلب، ما به روشهایی نیاز داریم که وقتی فراخوانی میشوند، بر اساس زمینه یا دادههای خاصی که در ابتدا با آن مرتبط بودند رفتار کنند.
اینجاست که الگوی روش Prebound وارد بازی می شود. این به ما اجازه می دهد تا یک متد را از قبل به برخی از داده ها یا زمینه ها متصل کنیم، بنابراین هنگامی که متد در نهایت فراخوانی می شود، ذاتاً زمینه خود را بدون اینکه به طور صریح گفته شود، می شناسد.
به یک سیستم رویداد محور فکر کنید، مانند یک جعبه ابزار رابط کاربری گرافیکی، که در آن اجزای مختلف رابط کاربری در هنگام تعامل با آن، اقدامات خاصی را آغاز می کنند. فرض کنید شما مجموعهای از دکمهها دارید و هر دکمه با کلیک کردن باید برچسب خود را نشان دهد.
بهجای ایجاد روشهای جداگانه برای هر دکمه، میتوانید از یک روش استفاده کنید، اما آن را به دادههای دکمه مربوطه از قبل متصل کنید، و به روش اجازه میدهد ذاتاً «بداند» کدام دکمه آن را فعال کرده و چه برچسبی را باید نمایش دهد.
الگوی روش Prebound بر روی تمرکز دارد روشها را قبل از اجرای روش به دادهها یا زمینههای خاص متصل میکند. این روش، پس از محدود شدن، نیازی به متن صریح در طول فراخوانی ندارد. در عوض، بر روی دادههای پیشباوند عمل میکند و یک تعامل یکپارچه و ظریف را تضمین میکند.
بیایید ببینیم این در عمل چگونه کار می کند. ما ایجاد خواهیم کرد Button
کلاسی که حاوی برچسب و یک روش است که کلیک ها را مدیریت می کند. هنگامی که دکمه کلیک می شود، برچسب آن چاپ می شود:
class Button:
def __init__(self, label):
self.label = label
# Prebinding the display_label method to the current instance
self.click_action = lambda: self.display_label(self)
def display_label(self, bound_button):
print(f"Button pressed: {bound_button.label}")
def click(self):
self.click_action()
برای آزمایش این موضوع، بیایید دو دکمه مختلف ایجاد کنیم و روی هر یک از آنها “کلیک” کنیم:
buttonA = Button("Submit")
buttonB = Button("Cancel")
buttonA.click()
buttonB.click()
همانطور که انتظار می رفت، با کلیک بر روی هر دکمه خروجی مناسب تولید می شود:
Button pressed: Submit
Button pressed: Cancel
با فعال کردن روشها برای آگاهی دقیق از زمینه خود قبل از فراخوانی، الگوی روش Prebound روشی را سادهسازی میکند و یک رویکرد شهودی را برای اقدامات خاص زمینه ارائه میکند.
الگوی شیء نگهبان
در توسعه نرم افزار، گاهی اوقات ما با چالش تمایز بین آن ها مواجه می شویم عدم وجود یک مقدار و مقداری که در واقع روی آن تنظیم شده است None
یا پیش فرض دیگری. صرفاً تکیه بر مقادیر پیش فرض معمولی ممکن است کافی نباشد.
این الگوی شیء نگهبان راه حلی برای این معضل ارائه می دهد. با ایجاد یک شی منحصر به فرد و غیر قابل اشتباه که به عنوان نگهبان عمل می کند، می توانیم بین مقادیر واقعی و پیش فرض تفاوت قائل شویم.
یک سیستم کش را در نظر بگیرید که در آن کاربران می توانند مقادیر را ذخیره و بازیابی کنند. یک چالش وجود دارد: چگونه بین کلیدی که هرگز تنظیم نشده است، کلیدی که با مقدار تنظیم شده است تفاوت قائل شوید None
و کلیدی که از حافظه پنهان خارج شده است؟ در چنین سناریویی، صرفاً بازگشت None
زیرا یک کلید گم شده می تواند مبهم باشد. است None
مقدار واقعی مرتبط با کلید، یا اصلاً کلید در حافظه پنهان وجود ندارد؟ با استفاده از الگوی شیء سنتینل، میتوانیم وضوح را در این مواقع فراهم کنیم.
الگوی شیء Sentinel حول محور ایجاد یک شی منحصر به فرد می چرخد که نمی تواند با هیچ داده قانونی در برنامه شما اشتباه گرفته شود. این شی به علامت غیرقابل انکار تبدیل می شود که یک شرط خاص، مانند یک مقدار گمشده، برآورده شده است:
# Our sentinel object
MISSING = object()
class Cache:
def __init__(self):
self._storage = {}
def set(self, key, value):
self._storage(key) = value
def get(self, key):
# Return the value if it exists, otherwise return the sentinel object
return self._storage.get(key, MISSING)
حال گمشده ها را متمایز می کنیم و None
ارزش های. وقتی یک شی را با اضافه می کنیم None
به عنوان یک مقدار به a Cache
شی، ما قادر خواهیم بود با جستجوی آن با استفاده از کلید آن، آن را پیدا کنیم:
# Usage
cache = Cache()
cache.set("username", None)
# Fetching values
result = cache.get("username")
if result is MISSING:
print("Key not found in cache!")
else:
print(f"Found value: {result}")
این مقدار آبجکتی را که کلید آن است، خروجی می دهد username
:
Found value: None
از طرف دیگر، ما نمیتوانیم یک شی غیر موجود پیدا کنیم:
missing_result = cache.get("non_existent_key")
if missing_result is MISSING:
print("Key not found in cache!")
این به ما می دهد:
Key not found in cache!
الگوی شیء Sentinel راهی روشن برای نمایش مقادیر گمشده یا موارد خاص ارائه میکند، و تضمین میکند که کد شما مبهم و قابل درک است.
نتیجه
در این مقاله، ما سه الگوی متمایز را کشف کردیم – the الگوی شی جهانی، الگوی روش Prebound، و الگوی شیء نگهبان. هر یک از این الگوها به چالش ها و سناریوهای منحصر به فرد برنامه نویسی پایتون می پردازد.
این الگوی شی جهانی بر سیستم ماژول انعطافپذیر پایتون و قدرت تکتونها در مدیریت حالت تاکید میکند. این الگوی روش Prebound چالشهای مرتبط با متدهای اتصال به کلاس یا اشیاء نمونه را به زیبایی حل میکند و قابلیتهای شی گرا پایتون را برجسته میکند. در همین حال، الگوی شیء نگهبان پویایی پایتون را به نمایش می گذارد و ابزار قدرتمندی برای سیگنال دادن به موارد خاص یا رفتارهای پیش فرض ارائه می دهد.
همراه با مثال های دنیای واقعی نه تنها به نشان دادن کاربردهای واقعی این الگوها کمک می کند، بلکه اجرای آنها در پایتون را ملموس تر می کند. پس از مطالعه مجدد این مقاله، باید بتوانید شکاف بین درک مفهومی و کاربرد عملی الگوهای طراحی اختصاصی پایتون را پر کنید.
منتشر شده در 1402-12-26 11:36:03