معرفی دیزاین‌پترن Observer

دیزاین‌پترن چیست؟

دیزاین‌پترن‌ها (Design Pattern)، راه‌حل‌هایی معمول برای حل مشکلات رایج موجود در طراحی نرم‌افزار هستند. آنها علاوه بر ارائه‌ی راه‌حلی منعطف، زبان مشترکی بین افراد تیم به شمار می‌روند تا ارتباط کارآمدتری داشته باشند! مثلاً رضا می‌گوید «یه آبزرور برای این قسمت نوشتم!» و سعید می‌گوید «آها! کارت درسته رفیق!»، زیرا برنامه‌نویسان تیم با دیزاین‌پترن‌ها آشنا هستند و می‌دانند که چرا استفاده می‌شوند و چه نیازی را برطرف می‌کنند! اگر هنوز فکر می‌کنید که توضیحات فوق گنگ است، خواندن این مقاله را متوقف کرده و ابتدا مفهوم دیزاین‌پترن را به طور مفصل بیاموزید.

مسئله: فروشگاه و تغییر قیمت

وضعیت بازار و مروّت خوب نیست و مسئولین هم دستشان به استعفا نمی‌رود. فروشگاه «دیدی‌حالا» معتقد است که بی‌خبری، خوش‌خبری نیست و می‌خواهد مشتریانش را از تغییر قیمت محصول ویژه‌اش باخبر کند. مدیر فروشگاه تاکید کرده که باید هر مشتری به دلخواه خود وارد این فرآیند شود و هر زمان که خواست از آن انصراف دهد.

راه‌حل: Observer Pattern

تعریف این الگو را از کتاب معروف Gang of Four ببینیم:

Defines a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.

این پترن، وابستگی یک به چندی میان آبجکت‌ها تعریف می‌کند، به نحوی که اگر یک آبجکت تغییر حالت دهد، تمام آبجکت‌های وابسته اطلاع یافته و به‌روز شوند. این الگو به نام‌های Dependents و Publish-Subscribe نیز شناخته می‌شود و یکی از الگوهای رفتاری (Behavioral Patterns) به حساب می‌آید.

دو اصطلاح مهم

  • سوژه (Subject): این همان «یک آبجکت»ای است که در تعریف دیدیم. سوژه یک حالت (State) دارد که می‌تواند تغییر کند و باید آبجکت‌های نامحدودی را به عنوان بیننده (Observer) خود بپذیرد.
  • بیننده (Observer): در این الگو، آبجکت‌هایی داریم که از تغییرات سوژه باخبر می‌شوند و هر زمان که لازم باشد، از نظاره‌کردن سوژه انصراف می‌دهند.

ساختار

Observer design pattern (Head First Design Patterns)
Observer design pattern (Head First Design Patterns)

همانطور که ملاحظه می‌کنید برای Subject و Observer، اینترفیس (Interface) داریم و بعد هرکدام را پیاده‌سازی می‌کنیم. مطمئناً می‌دانید که اینترفیس‌ها پیاده‌سازی (Implementation) ندارند و کلاس‌های دیگری آنها را پیاده می‌کنند.

کاربردپذیری

  • زمانی که نیاز داریم با تغییر یک آبجکت، آبجکت‌های دیگری تغییر کنند و نمی‌دانیم که دقیقاً چند Observer وجود دارد. پس باید ساختاری داشته باشیم که در صورت لزوم، بی‌آنکه کلاس‌هایمان دچار تغییر شوند، هر آبجکتی را به لیست Subscriberها اضافه یا از آن حذف کنیم.
  • زمانی که باید یک آبجکت قابلیت خبردادن به آبجکت‌های دیگر را داشته باشد، بدون اینکه ماهیت آنها را بداند یا وابستگی محکمی بینشان برقرار باشد.

و...

پیاده‌سازی

بدخواهان PHP بدانند که این زبان از قدیم‌الایام دو اینترفیس برای Subject و Observer داشته است! ? می‌دانید که خواندن و نوشتن کد در ویرگول زجرآور است، برای همین کدهای مثال را در یک مخزن گیت‌هاب قرار داده‌ام و سرانجام کار را در اینجا می‌نویسم:

$product = new Product(300000);
$customer1 = new Customer('Muhammad');
$customer2 = new Customer('Parsa');
$customer3 = new Customer('Matin');

$product->attach($customer1);
$product->attach($customer2);
$product->attach($customer3);

$product->setPrice(350000);

به محض تغییر قیمت، خروجی زیر را خواهیم داشت:

Muhammad: The price has changed!
Parsa: The price has changed!
Matin: The price has changed!

این خروجی نشان می‌دهد که مشتریان ما از تغییر قیمت باخبر شدند و هدف ما هم از استفاده‌کردن Observer Pattern همین بود!


منابعی که این مقاله را شکل دادند:


شاید این نوشته‌ها هم برایتان جالب باشند:

معرفی دیزاین‌پترن Singleton