الگوی طراحی Observer یکی از کاربردیترین الگوهای طراحی است. این الگو یک الگوی Behavioral است. قبلا در مورد دسته بندی الگوهای طراحی توضیح داده بودیم. هدف الگوی طراحی Observer ایجاد بستری برای مشاهده دائم یک مقدار، رویداد و… است و اینکه در صورت تغییر این مقدار، بتوانیم واکنش مناسب را در سریعترین زمان ممکن انجام دهیم. با این توضیح کوتاه احتمالا بیشتر سردرگم شدید! اما نگران نباشید؛ بیایید با یک مثال از دنیای واقعی، کارکرد این الگو را بررسی کنیم.
فرض کنید شما علاقه مند به اخبار ورزشی هستید. برای دنبال کردن اخبار ورزشی، یک مجله معتبر و خوب پیدا میکنید. در اشتراک ماهانه/هفتگی آن مجله عضو میشوید. با اینکار، هر بار که مجله فوق شماره جدیدی چاپ کند، موظف است این نسخه جدید را برای شما ارسال کند. در نتیجه این نسخه جدید برای شما ارسال میشود و شما قادر خواهید بود تا اخبار ورزشی جدید را در این شماره پیدا کنید. اما این چرخه تا کی ادامه خواهد داشت؟ مسلما تا زمانی که شما اشتراک ماهانه/هفتگی را تمدید کنید. پس اگر اشتراک خود را تمدید نکنید و یا بصورت داوطلب انصراف دهید، دیگر نسخههای جدید مجله برای شما ارسال نخواهد شد.
الگوی طراحی Observer در واقع پیاده سازی ایدهی فوق است. در این الگو کلاس مورد نظر ما یک لیست از اعضا دارد. بخشهای دیگر برنامه میتوانند در این لیست عضو شوند. در صورتی که تغییری در کلاس ما اتفاق بیوفتد، این تغییر به همه اعضای لیست اعلام خواهد شد. اعضا در واقع هر بخشی از برنامه است که میخواهد تغییری را در کلاس ما نظارت کند. به عنوان یک مثال کاربردی فرض کنید دو موجودیت مشتری و فروشگاه داریم. یکی از مشتریها به یک برند خاص(مثلا اپل) خیلی علاقه دارد و هر روز برای اینکه بداند مدل جدید گوشی این برند در فروشگاه موجود است یا خیر، به فروشگاه سر میزند.
در مقابل، مسئول فروشگاه میتواند با موجود شدن هر محصول، صدها یا حتی هزاران پیام به تمام مشتریان ارسال کند(ایمیل، پیامک و…) که مشخص است این روش نه تنها مشکلی را رفع نمیکند، بلکه سایر مشتریان را نیز ناراضی خواهد کرد. البته مشخص است که این روش برای فروشگاه نیز پرهزینه خواهد بود. اما باید راهی وجود داشته باشد که مراجعههای بی فایده مشتریان را کاهش دهد. فروشگاه باید بتواند به کمک روشی بهینهتر، از اتلاف وقت مشتریان جلوگیری کند.
راه حل
آن چیزی که مورد علاقه مشتریان است(گوشی iPhone یا هر کالایی در مثال بالا)، در این الگو Subject نامیده میشود اما از آنجا که این object(کالا) باید به سایر object ها(مشتریان) تغییر وضعیت خود را اعلام کند، ما آن را Publisher یعنی نشردهنده مینامیم. تمام object های دیگر(مشتریان) که میخواهند تغییر وضعیت object مورد نظر(کالای دلخواه) را رسد کنند، subscribers یا مشترکین نامیده میشوند.
الگوی طراحی Observer پیشنهاد میدهد که مکانیزم عضو شدن را در کلاس publisher پیادهسازی کنیم. با اینکار هر نوع object ای میتواند از تغییر وضعیت object مورد نظر مطلع شود. هر object ای که نیاز به این اطلاعات نداشته باشد هم به راحتی میتواند خود را از لیست مشترکین حذف کند. نترسید! همه چیز آنقدر که به نظر میرسد پیچیده نیست. در واقع، این مکانیزم تنها به دو بخش نیاز دارد. اول یک آرایه(array) که لیست مشترکین را در خود نگهداری کند و دوم توابع public که دسترسی لازم را برای عضویت و لغو عضویت دیگر object ها فراهم کند.
تصویر بالا این دو بخش را در کلاس Publisher نشان میدهد. حالا اگر اتفاق مهمی برای Publisher رخ دهد، به راحتی میتواند این اتفاق را به مشترکین خود خبر دهد. این کار از طریق متد notification یا همان اعلان انجام میشود.
برنامه های واقعی ممکن است ده ها کلاس مشترک داشته باشند که به دنبال ردیابی وقایع در کلاس ناشر هستند. شما نمی خواهید ناشر را با همه این کلاسها جفت کنید. علاوه بر این، حتی اگر قرار است کلاس ناشر شما توسط object های دیگری مورد استفاده قرار گیرد ، از قبل درباره همه آنها اطلاعی ندارید. یعنی نمیدانید که آنها را با چه روشی مطلع کنید.
به همین دلیل بسیار مهم است که همه مشترکین همان interface یا رابط را پیاده سازی کنند که مورد قبول ناشر است و ناشر فقط از طریق آن رابط با آنها ارتباط برقرار کند. این رابط باید روش اعلان را به همراه مجموعه پارامترهایی تعریف کند که ناشر می تواند از آن برای انتقال برخی داده های متنی به objectها استفاده کند. حال مشترکین با دریافت این دادهها از تغییر وضعیت ناشر مطلع میشوند.
به تصویر بالا نگاه کنید. در واقع interface همهی مشترکین را ملزم به داشتن متدی public مثلا با نام update میکند. در این حالت کلاس ناشر میتواند متدی مثلا به نام notifySubscribers داشته باشد که با هر بار تغییر وضعیت، این متد فراخوانی شود. در داخل این متد، با صدا زدن متد update تک تک مشترکین، وضعیت جدید را به آنها اعلام میکند. در این حالت، ناشر نیازی به دانستن جنس مشتریان و ویژگیهای آنها ندارد. فقط چون میداند همهی آنها تابعی به نام update دارند که از طریق آن بروز رسانی میشوند، تغییر وضعیت را از طریق همین متد به آنها اعلام میکند.
دیاگرام کلی این الگو به شکل زیر است:
اگر برنامه شما چندین ناشر داشته باشد و بخواهید تمام مشترکین با این ناشران سازگار باشند، میتوانید فراتر رفته و یک interface تا همهی ناشران از آن پیروی کنند. در این interface تنها نیاز است تا متدهای عضویت و لغو عضویت را تغریف کنید تا همهی ناشران آنها را با یک نام مشترک پیادهسازی کنند. در واقع این رابط به مشترکین این امکان را میدهد تا بدون اینکه مستقیما با ناشران رابطه داشته باشند، بتوانند وضعیت آنها را رصد کنند.
در این آموزش سعی کردیم تا مفهوم الگوی طراحی Observer را بیان کنیم و بدانیم که این الگو چه چالشی را برطرف خواهد کرد. برای پیادهسازی عملی این الگو، بسته به زبان برنامهنویسی مورد نظر، نمونه کدهایی وجود دارد که اکنون قادر به درک آنها هستید.
موفق و پیروز باشید.
عالی دمت گرم
خواهش میکنم. خوشحالم که مورد رضایت قرار گرفته