بایگانی

بایگانی برای دسته ی ‘الگوهای طراحی’

عمق وراثت (Depth of Inheritance)

هفته قبل رامین در جلسات باز نرم‌افزاری تبریز در مورد الگوی طراحی Decorator  صحبت می‌کرد. سوالی که توسط تعدادی از دوستان مطرح شد این بود که چرا از وراثت به جای این الگو استفاده نکنیم؟ دلیلی که توسط رامین به آن اشاره شد این بود که رفتار و ویژگی‌های جدید با استفاده از این الگو در زمان اجرا به نمونه کلاس‌ها اضافه می‌شود نه به خود کلاس. در حالیکه با استفاده از وراثت رفتار و ویژگی‌های جدید به زیرکلاس اضافه می‌شود و در نتیجه این ویژگی‌ها به همه نمونه‌های آن افزوده می‌شود.

وراثت در برایر Decorator

وراثت در برایر Decorator

اما مشکل دیگری که برای وراثت به آن اشاره شد افزایش تعداد زیرکلاس‌ها و عمق وراثت بود. در این پست می‌خواهیم کمی بیشتر در مورد عمق وراثت بحث کنیم.

عمق وراثت یکی از متریک‌های طراحی شی‌گرا می‌باشد که به این شکل تعریف می شود: “حداکثر فاصله یک گره از گره پدر درخت”. برای نمونه من درخت وراثت را برای کلاس Hidden از فریم‌ورک Asp.NET MVC رسم کردم و همانطوریکه در تصویر مشخص هست عمق این درخت ۴ هست. به یک نکته توجه کنید که در بسیاری از زبانها همه کلاس‌ها از یک کلاس پایه ارث می‌برند حتی اگر به طور صریح در کد شما به آن اشاره نشده باشد. برای نمونه در سی شارپ همه کلاسها از کلاس Object ارث می‌برند پس هر کلاسی که شما ایجاد کنید حداقل دارای عمق یک خواهد بود.

 

عمق وراثت کلاس Hidden

عمق وراثت کلاس Hidden

افزایش عمق وراثت یک سری معایب همراه با یک سری مزایا دارد. با افزایش عمق، تعداد متدهای که به ارث برده می‌شود افزایش می‌یابد و این باعث می‌شود پیش‌بینی رفتار کلاس سخت‌تر شود.  با افزایش عمق، میزان پیجیدگی افزایش و در نتیجه احتمالا تعداد خطاها افزایش، قابلیت نگهداری و تست‌پذیری نرم‌افزار کاهش می‌یابد.  اما فاکتور مثبت افزایش عمق، افزایش قابلیت استفاده مجدد خواهد بود.

 

حداکثر مقدار قابل قبول برای عمق وراثت چقدر است؟ هیچ مقدار استانداردی برای حداکثر مقدار بهینه عمق وراثت تا بحال اعلام نشده است. مقادیر توصیه شده از ۵ تا ۸ متغییر است. برای نمونه مستندات مایکروسافت ویژوال استودیو مقدار ۵ را پیشنهاد می‌کند در حالیکه برای نمونه در سورس Asp.net MVC که مربوط به خود این شرکت هست عمقی تا هفت را می‌توان مشاهده کرد. شاید دلیلی که نمی‌توان یک حداکثر مقدار بهینه برای این متریک تعیین کرده در متفاوت بودن ماهیت سیستم‌های نرم‌افزاری باشد. برای مثال شاید برای یک فریم‌ورک توسعه وب مقدار ۵، ۶ قابل قبول است در حالیکه برای یک سیستم اتوماسیون اداری این اعداد یک مقدار بزرگ است.

حداکثر عمق کلاس در فریم‌ورک ASP.NET MVC

حداکثر عمق کلاس در فریم‌ورک ASP.NET MVC

الگوهای طراحی در قالب یک فایل

تا به حال چند تن از دوستان پیشنهاد داده بودند که، پستهای مربوط به موضوع الگوهای طراحی را در قالب یک فایل برای دانلود قرار بدهم. ولی من همیشه دوست داشتم ۲۳ الگوی مشهور GOF را در وبلاگ بررسی کنیم و بعد از ویرایش و بررسی مجدد آنها را برای دانلود قرار بدهم. ولی متاسفانه هرگز فرصت کافی برای اینکار به نحوی که در ذهن داشتم به دست نیامد. البته بعضی از الگوها را که بررسی نشده است به صورت پیش نویس حتی روی کاغذ نوشتم که امیدوارم به زود بعد از بررسی مجدد، آنها را در وبلاگ منتشر کنم و برای دانلود قرار بدهم.

فایلی که آماده شده است نسخه بدون ویرایش پست های وبلاگ هستند. پس از دوستان تقاضا دارم نظر خود را درباره نواقص و اشکالات آن با من در میان بگذارند. تا به کمک هم آنها را اصلاح و کاملتر کنیم. برای دانلود فایل به این لینک مراجعه کنید.

لینک دانلود الگوهای طراحی

الگو های طراحی (Design Pattern)

الگو های طراحی (Design Pattern) :

 

کسی وجود دارد که قبلاً مسله شما را حل کرده است.

در مهندسی نرم افزار یک الگوی طراحی، یک روش حل قابل تکرار برای مسائلی هست که عموماً در طراحی نرم افزار با آن برخورد می کنیم. یک الگوی طراحی یک قالب یا شرح برای چگونگی حل مسائلی است که می تواند در شرایط مختلف استفاده شود.یک الگوی طراحی، راه حلی است که برای مستند سازی ارزشمند تشخیص داده شده است، بطوریکه توسعه دهند گان دیگر می توانند آن را در حل مسائل مشابه به کار ببرند.همانگونه که طراحی شی گرا ادعا می کند که استفاده مجدد از کتابخانه ها و قطعات را افزایش می دهد، ادعا می شود که استفاده از الگو های طراحی، استفده مجدد از کتابخانه ها و قطعات را افزایش می دهد. 

الگو ها تکنیک هایی هستند که افراد زمانی از آنها برای حل مسائل خاص استفاده کردند. و به عنوان راه حل های خوب شناخته شده اند. سپس این تکنیک ها مستند سازی شده اند تا توسعه دهندگان هنگام برخورد با مسائل مشابه از این مستندات استفاده کنند و مسائل خود را حل کنند.

 

تاریخچه الگو های طراحی :

استفاده از الگوها برای اولین بار به ذهن یک معمار به نام الکساندر خطور کرد. الکساندر با این مشکل روبرو شد که یک طرح خوب و با کیفیت برای یک ساختمان چگونه می تواند باشد. او برای حل مشکل خود، ساختمانها، خیابانها، شهرک ها و هر مکانی که یک انسان برای خودش می سازد را مورد مطالعه و بررسی قرار داد. او کشف کرد که بناهای خوب از نظر طراحی دارای ویژگیهای مشترک هستند. او کشف کرد که بناهای خوب دارای ویژگیهای مشابه هستند واین ویژگیهای مشابه را الگو نامید.

هر الگو بیانگر یک مسئله و مشکل است که می تواند بارها و بارها روی بدهد همراه با راه حل آن مسئله، وشما می تواند از این راه حل برای میلیون ها بار استفاده کند بدون نیاز مجدد برای پیدا کردن راه حل.

در اوایل دهه ۱۹۹۰، بعضی از توسعه دهندگان نرم افزار با کارهای الگساندر برخورد کردند.آنها با این سوال روبرو شدند که اگر الگو های طراحی معماری در این رشته به صورت صحیح جواب می دهد آیا می توان الگوهای را برای طراحی نرم افزار بوجود آورد.

  • در نرم افزار چه مسائل وجو دارد که بارها رخ می دهد و تقریبا با روشهای مشابه می توان آنها را حل کرد؟
  • آیا امکان استفاده از مفهوم الگوها در طراحی نرم افزار وجود دارد، آیا می توان راه حل های را برا اساس الگوها بعد از شناسایی الگوها ایجاد کرد.

سوالات بالا، سوالاتی بودند که توسعه دهندگان مطرح کردند و پاسخ آن را یافتند. پاسخ سوال بلی بود. مرحله بعدی شناسایی الگوها بود و توسعه استانداردهای برای مستند سازی الگوها.

در اوایل دهه ۱۹۹۰، افرادی زیادی روی الگوهای طراجی کار می کردند. اما چهار نفر به نام های، گاما، جاکوبسون، هلم و ولسایدز بیشترین تاثیر را در این زمینه با نوشتن کتابی به نام

“Design Pattern: Elements of Reusable Object-Oriented Software”، داشتند. این چهار نویسنده به Gang of Four مشهور است. آنها در این کتاب ائده استفاده از الگوها را در طراحی نرم افزار به کار بردند.و یک فرمت استاندارد را برای مستندسازی الگوها ایجاد کردند. ۲۳ نوع از الگوها را دسته بندی کردند و …. به مرور زمان فرمت های استاندارد دیگری برای مستند سازی الگوها پیشهناد شد.

 

 قالب مستند سازی برای الگوهای طراحی :

 

 

نام الگو

یک نام خوب و مفید برای الگو

هدف (intent)

یک جمله کوتاه و مختصر درباره چیزی که الگو انجام می دهد. (تعریف مسله و راه حل به صورت مختصر و مفید)

نام مستعار

نام های دیگری که الگو با آن شناخته می شود.

ساختار

یک نمایش گرافیکی از الگو

اجزاء تشکیل دهنده (Participants)

کلاس ها و اشیائ که در الگو شرکت دارند (وجود دارند).

همکاریها (Collaborations)

چگونه اجزای تشکیل دهنده با هم همکاری می کنند تا وظایفشان را انجام دهند.

نتایج‌ (Consequences)

نتایج استفاده از الگوی مورد نظر

پیاده سازی

تکنیک های برای پیاده سازی الگوی مورد نظر

نمونه کد

تکه کدی برای پیاده سازی یک نمونه

الگو های مرتبط

الگوهای طراحی دیگری که ارتباط نزدیگ با الگوی مورد نظر دارند.

 

دسته بندی الگو ها :

۱-   الگوهای بوجود آورنده(Creational Pattern): همه الگو های که در این دسته قرار می کیرند در ارتباط با روش های ایجاد اشیاء هستند.

۲-   الگوهای ساختاری(Structural Patten): این نوع الگوها شرح می دهند چگونه اشیاء و کلاس ها می توانند در ساختارهای بزرگتر باهم ترکیب شوند.

۳-      الگوهای رفتاری(Behavioral Pattern): این نوع الگو ها روی ارتباط اشیاء با یکدیگر تمرکز دارند.

 

Creational

Structural

Behavioral

Factory Method

Abstract Factory

Builder

Prototype

Singleton

Adapter

Bridge

Composite

Decorator

Flyweight

Façade

Proxy

Interpreter

Template Method

Chain of Responsibility

Command

Iterator

Mediator

Memento

Observer

State

Strategy

Visitor

 

فهرست الگوهای طراحی

 

 

الگوی Composite

همانطوریکه روی صندلی نشسته اید به بدن خود تان توجه کنید و آنرا مورد بررسی قرار بدهید، شاید بدن خود را به صورت ترکیبی از چندین شی مانند دست، پا، چشم و …  ببینید. سپس با دست خود یک کتاب را بردارید و شروع به ورق زدن آن بکنید، مشاهده می کنید که یک کتاب از ده ها صفحه تشکیل شده است و هر صفحه از چندین پارگراف و هر پار گراف از چندین سطر تشکیل شده است.  روی آیکون My Computer کلیک می کنید، دریواهای که کامپیوترتان دارید نشان داده می شود، روی یکی از دریواها کلیک می کنید، لیست فایل ها و folder های آن دریوا نشان داده می شود، سپس روی یکی از folder ها کلیلک می کند، مشاهده می کند که خود آن folder، از چندین folder و یا فایل تشکیل شده است. در هر کدام از نمونه های بالا، همانطوریکه دیدید یک شی ممکن شامل چندین شی ساده یا مرکب دیگر نیز باشد، آن شی باید بداند که چگونه این اشیاء را نگهداری و مدیریت کند و هر چه تعداد اینگونه اشیاء مرکب در سیستم افزایش یابد، سیستم پیچیده تر خواهد شد. شما برای حل این مشکل چه پیشنهادی دارید و چه راه حلی ارائه می کنید؟

اجازه بدهید کار را با یک مثال ادامه دهیم. برای مثال فرض کنید که می خواهیم یک برنامه ایجاد کنیم که فایل سیستم ویندوز را شبیه سازی کند. در فایل سیستم ویندوز ما دو شی اصلی به نامه های Folder و فایل داریم. Folder ها می توانند از فایل ها یا Folder ها دیگر تشکیل شوند، در حالیکه فایل ها نمی توانند شامل مولفه ای دیگری از فایل سیستم باشند. برای این مثال می توان طراحی های گوناگونی را ارائه کرد. یک طراحی می تواند بدین صورت باشد که، یک اینترفیس مشترک برای هر دو شی موجود در مسئله تعریف کنیم، که شامل متدهای باشد که در هر دو شی وجود دارند. شکل زیر طراحی حاصل را نشان می دهد.

با این طراحی  Clinet می تواند یک مجموعه از اشیاء FileSystemComponent را ایجاد کند. و با استفاده از متد addComponent، شی  DirComponent، نمونه های مختلفی از FileSystemComponents را به DirComponent اضافه کند.

هنگامیکه Clinet بخواهد سایز هر کدام از این اشیاء را استخراج کند، به سادگی متد getComponentSize را فراخوانی کند، Client نباید از نحوه محاسبه و عملیاتی که برای اندازه گیری سایز یک مولفه صورت می گیرد آگاه باشد. در این مورد، client با هر دو شی FileComponent و DirComponent به یک صورت رفتار می کند.

Clinet  در مورد متد مشترک getComponentSize، با هر دو شی  FileComponent و DirComponent رفتار یکسانی را دارد. اما Clinet   برای فراخوانی متدهای مانند addComponent و getComponent نیاز دارد که دو شی را از همدیگر تشخیص دهد، چونکه این متدها فقط برای DirComponent تعریف شده است. به همین دلیل client نیاز دارد تا نوع شی مورد نظر را برای فراخوانی این متدها چک کند تا مطمئن شود که با یک نمونه از DirComponent سر و کار دارد.  برای بهبود این طراحی بگونه ای که نیازی به تشخیص تفاوت بین دو شی وجود نداشته باشد، طراحی را به چه صورت تغییر می دهد.

ما می خواهیم طراحی را بگونه ای تغییر دهیم که clinet  نیازی به تشخیص شی مرکب DirComponent از FileComponent نداشته باشد، و با هر دو شی به یک صورت رفتار کند.

طراحی را می توانیم به این صورت تغییر دهیم که، متدهای addComponent و getComponent را به اینترفیس مشترک FileSystemComponent  انتقال دهیم، و یک پیاده سازی پیش فرض برای این متدها انجام دهیم و اینترفیس مشترک FileSystemComponent   را به یک کلاس abstract تغییر دهیم. پیاده سازی پیش فرض برای این متدها بخاطر FileComponent  هست و کار خاصی را انجام نمی دهد. اما کلاس DirComponent این متدها را بازنویسی مجدد می کند تا پیاده سازی خاص خود را انجام دهد.

با این کار مشکل قبلی ما حل می شود، چون کلاس پدر FileSystemComponent، دارای یک پیاده سازی پیش فرض برای متدهای addComponent و getComponent هست، و دیگر clinet   نیاز به کنترل نوع شی برای فراخوانی این دو متد ندارد.

تصور کنید که می خواهیم یک متد جدید با نام  removeComponent را به کلاس DirComponent اضافه کنیم، در اینصورت این متد را به پدر FileComponent نیز اضافه می کنیم و یک پیاده سازی پیش فرض برای این متد در نظر می گیریم.

با طراحی بالا ما توانستیم مشکل خود را حل کنیم، اما روشی که برای غلبه بر مسئله استفاده کردیم، الگوی Composite نام دارد. ما در مواقعی از این الگو استفاده می کتیم که یک شی پیچیده داریم و می خواهیم آنرا به یک سلسله مراتب از اشیاء کل و جز (part-whole hierarchy) تجزیه کنیم. یا همانند مثال بالا،  client قادر باشد تفاوت بین اشیاء مرکب (DirComponent) و اشیاء منفرد را نادیده بگیرید. و client با همه اشیاء موجود در ساختار مرکب بصورت یکسان رفتار کند.

کلاس دیاگرام این الگو به صورت زیر است:

در دیاگرام بالا کلاس Leaf، کلاس های هستند که دارای فرزند نیستند مانند کلاس FileComponent در مثال.

کلاس Composite، کلاسی مانند DirComponent در مثال می باشد. در این کلاس رفتارهای مربوط به مولفه های که دارای فرزند هستند تعریف می گردد.

کلاس FileSystemComponent همان کلاسFileSystemComponent با ویژگیهای که در بالا اشاره شد هست.

الگوی Iterator

یکی شی مرکب دارید، تمایل دارید اشیاء تشکیل دهنده این شی را چگونه ذخیره کنید، در یک آرایه، در یک ArrayList یا در یک ساختار دیگر. شما می توانید با توجه به علاقه و سبک کاری خود هر کدام از این ساختمان داده ها را برای اینکار استفاده کنید. اما اجازه بدهید روی مسئله را کمی تغییر دهیم، یک کلاس دیگر نیاز دارد به اشیاء موجود در این اشیاء دسترسی داشته باشد، برای اینکار حتما نیاز خواهد داشت که بداند شما اشیاء را در این شی به چه صورت ذخیره کرده اید. پس برای غلبه به این مشکل شما نیاز دارید، متدهای را توسط شی مرکب ارائه دهید که کلاس های دیگر بدون اطلاع از نحوه ذخیره شدن اشیاء، به آنها دسترسی داشته باشند.

یک مسئله دیگر را در نظر بگیرید، ما چندین شی مرکب یا لیستی از داده ها داریم، بعضی از کلاس ها نیاز دارند تا به اشیاء و داده های موجود در این اشیاء یا لیست ها دسترسی داشته باشند، آیا می توانیم طراحی خود را به صورتی ارائه دهیم که یک کلاس، به روشی مشابه به لیست اشیاء یا داده ها دسترسی داشته باشد.

الگوی که می توانیم برای حل این مسئله بکار ببریم، الگوی Iterator نام دارد. این الگو یک اینترفیس تعریف می کند که امکان دسترسی نرتیبی به عناصر یک مجموعه را می دهد. هر کلاس که بخواهد به عناصر یک مجموعه دسترسی پیدا کند از طریق این اینترفیس عمل خواهد کرد که مستقل از پیاده سازی شی مرکب و کلاسی که این اینترفیس را پیاده سازی کرده است خواهد بود.

تصور کنید که یک کتاب از چند فصل تشکیل شده است و هر فصل به عنوان یک شی در سیستم در نظر گرفته شده است، می خواهیم اسامی فصول این یک کتاب را نمایش دهیم، برای اینکار ما نیاز داریم تا به لیست فصول آن کتاب دسترسی داشته باشیم، برای اینکار ما از الگوی بالا استفاده خواهیم کرد. طبق تعریف الگوی Iterator، ما در ابتدا نیاز داریم تا یک اینترفیس برای اینکار تعریف کنیم. ما به متدهای مانند بررسی اینکه عنصری بعدی در لیست وجود دارد یا نه، برگرداندن عنصر فعلی، برگرداندن عنصر بعدی، و برگشت به عنصر اول. سپس ما نیاز داریم تا این اینترفیس را پیاده سازی کنیم.

دیاگرام الگوی Iterator

تعریف اینترفیس IIterator

Public Interface IIterator

 Function FirstItem() As Object

 Function NextItem() As Object

 Function IsDone() As Boolean

 Function CurrentItem() As Object

End Interface

 

پیاده سازی اینترفیس IIterator

Public Class ConcreteIterator

 Implements IIterator

 Private List As New ArrayList

 Private Current As Integer = 0

 

 Public Sub New(ByVal VarList As ArrayList)

 List = VarList

 End Sub

 

 Public Function CurrentItem() As Object Implements IIterator.CurrentItem

 Return List(Current)

 End Function

 

 Public Function FirstItem() As Object Implements IIterator.FirstItem

 Current = 0

 If IsDone() Then

 Return List(Current)

 Else

 Return Nothing

 End If

 End Function

 

 Public Function IsDone() As Boolean Implements IIterator.IsDone

 If Current >= List.Count Then

 Return False

 Else

 Return True

 End If

 End Function

 

 Public Function NextItem() As Object Implements IIterator.NextItem

 Current += 1

 If IsDone() Then

 Return List(Current)

 Else

 Return Nothing

 End If

 End Function

End Class

 

تعریف اینترفیس Aggregate

Public Interface IAggregate

 Function CreateIterator() As IIterator

End Interface

 

پیاده سازی اینترفیس Aggregate و کلاس Book

Public Class Book

 Implements IAggregate

 Private _Name As String

 Private _Chapters As New ArrayList

 

 Public Property Name() As String

 Get

 Return _Name

 End Get

 Set(ByVal value As String)

 _Name = value

 End Set

 End Property

 

 Public Sub New()

 

 End Sub

 

 Public Sub New(ByVal VarName As String)

 _Name = VarName

 End Sub

 

 Public Sub Add(ByVal Chapter As Chapter)

 _Chapters.Add(Chapter)

 End Sub

 

 Public Function CreateIterator() As IIterator Implements IAggregate.CreateIterator

 Return New ConcreteIterator(_Chapters)

 End Function

End Class

 

 

تعریف کلاس Chapter

Public Class Chapter

 Private _Name As String

 Public Property Name() As String

 Get

 Return _Name

 End Get

 Set(ByVal value As String)

 _Name = value

 End Set

 End Property

 Public Sub New()

 

 End Sub

 Public Sub New(ByVal VarName As String)

 _Name = VarName

 End Sub

End Class

 

نحوه استفاده

Dim Book As New Book(“Book1″)

Book.Add(New Chapter(“Chapter 1″))

Book.Add(New Chapter(“Chapter 2″))

 

Dim Iterator As IIterator = Book.CreateIterator

Dim Ins As Chapter = Iterator.FirstItem

While Iterator.IsDone

 System.Console.WriteLine(Ins.Name)

 Ins = Iterator.NextItem

End While

 

 

الگوی Mediator

نمی دانم فارغ التحصیل شدید یا نه، اما همه ما در دوران دانشگاه همکلاسی ها و دوستان صمیمی زیادی داریم که، همیشه می خواهیم خبری از آنها داشته باشیم، اما بعدی از فارغ التحصیلی هزار و یک مشکل به سراغمان می آید. و اگر بخواهیم با تک و تک آنها ارتباط داشته باشیم برایمان خیلی سخت خواهد بود همینطور برای آنها. اما تقریبا همیشه فردی هست که، همه می خواهند با او ارتباط داشته باشند، پس مشکل حل شد ، پس فقط کافی است که ما نیز با این فرد تماس بگیرم تا خبری از همه بچه ها بدست آوریم.

 

در دنیای نرم افزار های شی گرا نیز ، اشیاء برای انجام دادن یک وظیفه با همدیگر ارتباط دارند. اما همانند مثال بالا، هر چه تعداد ارتباطات افزایش یابد، برنامه پیچیده تر خواهد شد و منجر خواهد شد که نگهداری برنامه نیز سخت تر شود و قابلیت استفاده مجدد نیز کاهش یابد.

برای مثال فرم زیر را در نظر بگیرید، این فرم برای رزور یک اتاق مهمانی در یک هتل استفاده می شود، طرز عملکرد فرم در زیر توضیح داده شده است.

هنگامیکه پنجره برای اولین بار نمایش داده می شود، فقط فیلد مربوط به تعداد مهمان ها و دکمه برگشت فعال است. کنترل های تاریخ، ساعت شروع و ساعت اتمام زمانی فعال می شوند که کاربر تعداد مهمان ها را وارد کند. اما فقط زمانهای را می تواند وارد کند که در آن موقع اتاقی با آن سایز موجود باشد. سپس گزینه سرویس ها فعال می شود. اگر تعداد مهمان ها پاک شود، باید تمام گزینه ها پاک و غیر فعال شوند.

ساعت شروع باید کوچکتر از ساعت اتمام باشد.

هنگامیکه کاربر تعداد مهمانها و ساعت و تاریخ را وارد می کند و یک نوع سرویس را انتخاب کرد، لیست غذا ها فعال می شود. با توجه به تاریخ، ساعت و نوع سرویس، لیست غذاهای ارائه شده متفاوت خواهد بود.

هنگامیکه حداقل یک نوع غذا انتخاب شد، و داده ها دیگر معتبر بودند، دکمه رزور فعال می شود.

شکل بالا، ارتباطات و روابط موجود بین اشیاء روی فرم را نشان می دهد. همانطوریکه داده می شود، هر شی حداقل دارای ۲ وابستگی است. همانطوریکه در بالا نیز گفته شده، وابستگی باعث پیچیده شدن منطق برنامه خواهد شد و این نگهداری سیستم را مشکل تر خواهد کرد و قابلیت استقاده مجدد را نیز کاهش خواهد داد. برای مثال تغییر در یکی از کلاس ها ممکن است، به تغییر در سایر کلاس ها منجر شود. شما برای حل این مشکل و کاهش تعداد وابستگی ها چه پیشنهادی دارید؟

برای حل مشکل می توانیم، مانند مثال اول عمل کنیم، یعنی دوستی را ایجاد کنیم که همه به جای کسانی که می خواهند با آنها ارتباط برقرار کنند، فقط با او ارتباط برقرار کند.یعنی در مثال دوم، ما یک کلاس جدید ایجاد کنیم که، به جای اینکه کلاس ها با یکدیگر بطور مستقیم ارتباط برقرار کنند، با کلاس جدید ارتباط بر قرار کنند و کلاس جدید مسئولیت ارتباط با کلاس دیگر را بعهده بگیرید. روشی که برای حل مسئله مطرح شد، الگوی Mediator نام دارد. در واقع این کلاس مسئولیت، مدیریت وابستگی ها را بعهده می گیرد. و با این کار تمام اشیاء، فقط یک وابستگی دارند آن هم با کلاس Mediator. شکل زیر نحوه ارتباطات مثال ۲ را، بعد از اعمال شی Mediator را نشان می دهد.

حالا زمانیکه یکی شی می خواهد با شی دیگر ارتباط برقرار کند، پیام خود را به کلاس Mediator، ارسال می کند. و کلاس Mediator همانند یک مسیریاب آن را به شی مورد نظر ارسال می کند. با استفاده از این الگو می توانیم به مزایا زیر دست یابیم:

  1. سادگی تغییر در برنامه : با استفاده از این الگو وابستگی میان کلاس های مختلف کاهش می یابد و در اکثر موارد فقط با تغییر در کلاس Mediator و یا ایجاد زیر کلاس های از این کلاس، می توانیم تغییرات مورد نظر را اعمال کنیم بدون اینکه تغییری در کلاس های دیگر بدهیم.
  2. افزایش قابلیت استفاده مجدد: با کاهش وابستگی میان کلاس، قابلیت استفاده مجدد کلاس ها افزایش می یابد.

ولی باید توجه داشت که کلاس Mediator باعث کاهش پیچیدگی وابستگی بین کلاس ها می شود، اما این پیچیدگی به درون ساختار Mediator منتقل می شود و ممکن است باعث شود که تغییر آن مشکل شود.

نمودار UML الگو ی Mediator

در نمودار بالا شی Mediator، یک اینترفیس برای ارتباط با اشیاء Colleague تعریف می کند که این اینترفیس توسط کلاس ConcreteMediator پیاده سازی می شود. و Colleague کلاس ها، کلاس های هستند که باهم ارتباط داشتند و ما این ارتباط و وابستگی را از آنها جدا کردم و در کلاس Mediator قرار دادیم.

الگوی Decorator

۲۱ خرداد ۱۳۸۶ ۹ دیدگاه

وارد فروشگاه می شوید، غرفه ها را یکی یکی نگاه می کنید، بدنبال یک هدیه مناسب برای یک شخص خاص هستید. با زحمت و وسواس زیاد آنرا انتخاب می کنید و به فروشنده تحویل می دهید و می گوید آنرا برایتان کادو و تزئین کند. فروشنده جعبه های تزیئنی مختلف را برای قرار دادن هدیه برای شما نشان می دهد تا یکی از آنها را انتخاب کنید. شما جعبه مورد نظر را انتخاب می کنید. و پیشنهاد می کنید در صورت امکان بعد از قرار دادن هدیه شما و پیچیدن آن در کاغذ کادو، یک شاخه کل روی آن بچسباند. کار تمام می شود. فروشنده می گوید قیمت هدیه ای که انتخاب کرده اید، X تومان است، قیمت جعبه Y تومان است و فیمت شاخه گل  Z تومان است. شما باید سر جمع X+Y+Z تومان را پرداخت کنید.

حالا فرض کنید شما خرید، خود را تمام کردید و هدیه را به شخص مورد نظر خود تقدیم کردید. اما از طرف مسئولین همین فروشگاه، شرکت شما برای طراحی سیستم سفارش فروشگاه در نظر گرفته شده است. این فرشگاه دارای کالاهای متعدد کادویی هست و همچنین دارای انواع زیادی از جعبه های تزئینی و وسایل برای تزئین کالاهای مختلف است. سیستم باید قابلیت این را داشته باشدکه قیمت کل را برای یک کالا با سایر وسایل تزئینی محاسبه کند. طراحی شما برای این مسئله به چه صورت می تواند باشد؟

یک طراحی برای این مسئله می تواند به صورت زیر باشد:  یعنی به این صورت عمل شود که، اگر مشتری، یک هدیه را بدون هیچ کالای تزئینی دیگر خرید، یک نمونه از خود آن کلاس ایجاد شود و قیمت آن، توسط متد قیمت برگشت داده شود. اگر یک هدیه نوع ۱با جعبه ۱ خریداری شود، نمونه ای از هدیه نوع ۱ با جعبه نوع ۱ ایجاد شود، و قیمت کل خرید برگشت داده شود.

اما در این حالت، اگر فروشگاه دارای دهها هدیه و جعبه مختلف باشد، و شما هر کدام از ترکیب های ممکن را بصورت یک کلاس جداگانه تعریف کنید، برای یک کار ساده شاید صدها کلاس داشته باشید که، بی شک مدیریت و تغییر در هر کدام از کلاس ها، هزینه زیادی را در بر خواهد داشت.

در حال طراحی اینترفیس (UI) برنامه هستید، ترجیح می دهید که اطراف بعضی از دکمه ها (button) یک نوار رنگی نازک باشد. اما دکمه های  که شما استفاده کرده اید، این قابلیت را ندارد. می خواهید خودتان این قابلیت را به دکمه ها اضافه کنید. شما این کار را به چه روشی انجام می دهید؟

طراحی های مختلفی را می توان برای  هر دو مسئله بالا ارائه داد. اما یک طراحی و راه حل خوب الگوی Decorator است.

در هر دو مثال بالا، ما می خواهیم یک رفتار جدید را به یکی شی اضافه کنیم. ولی می خواهیم بدون استفاده از وراثت این رفتار را به شی اضافه کنیم. این الگو اجازه می دهد، تا یک رفتار را بدون استفاده از وراثت و بصورت دینامیک به یک شی اضافه کنیم. نمودار کلاس این الگو بصورت زیر است:

 

شیی که می خواهیم رفتار جدیدی را به آن اضافه کنیم، همان ConcreteComponent، در نمودار بالا می باشد (شی دکمه در مثال دوم). و شیی که رفتار جدید را به شی ConcreteComponent، اضافه می کند. یکی از ConcreteDecorator ها، خواهد بود (نوار نازک در مثال دوم ). اما این رفتار جدید، چگونه اضافه می شود؟ دقیقا به همان صورتیکه ما هدیه را در داخل جعبه قرار دادم. اینجا نیز یک نمونه از کلاس مورد نظر را در داخل کلاس دیگر قرار می دهیم و اجازه می دهیم کلاس در برگیرنده بر روی آن کار کند. در پایین با مثال اول به بررسی کامل عملکرد این الگو خواهیم پرداخت.

در مثال اول، شما یک هدیه، یک جعبه و یک گل می خرید. فرضی کنید می خواهیم، مقدار کل را با الگوی Decorator محاسبه کنیم:

در ابتدا یک شیی از کلاس هدیه ۱ ایجاد می کنیم. این کلاس یک متد به نام قیمت برای محاسبه قیمت خود دارد.

هدیه ۱  قیمت ()

سپس مشتری یک جعبه را انتخاب کرده بود، و فروشنده هدیه را در داخل آن قرار داده بود. پس ما نیز همین کار را می کنیم، یعنی فرضا نمونه ای از جعبه ۱ را ایجاد می کنیم و شی هدیه ایجاد شده را در داخل آن قرار می دهیم. و هدیه را با جعبه تزئین می کنیم.

جعبه ۱ قیمت()

هدیه ۱  قیمت ()

 

در آخر مشتری خواسته بود، یک گل بر روی هدیه نصب شود. ما نیز همین کار را می کنیم، یک نمونه از گل ایجاد می کنیم. و هدیه را با آن تزئین می کنیم.

گل قیمت()

جعبه ۱ قیمت()

هدیه ۱  قیمت ()

 

حل مشتری مبلغ پرداختی را از فروشنده می پرسد. پس ما باید در این نقطه قیمت را محاسبه کنیم. در ابتدا ما متد قیمت را از بیرونی ترین، تزئین کننده فراخوانی می کنیم. یعنی در ابتدا متد قیمت را برای شی گل فراخوانی می کنیم. این شی قیمت شی بعدی یعنی جعبه را فراخوانی می کند.  و جعبه متد قیمت، هدیه اصلی را فراخوانی می کند. در این نقطه چون هدیه یک شی تزئین کننده نیست (بلکه یک شی ConcreteComponent است). قیمت خود را برگشت می دهد یعنی ۳۰۰۰۰٫ سپس جعبه قیمت خود را به قیمت برگشت داده شده توسط هدیه، اضافه می کند. و مجموع را برگشت می دهدیعنی ۳۱۰۰۰٫ در آخر نیز گل مقدار خود را به مقدار برگشت داده شده اضافه می کند و مجموع کل را برگشت می دهد یعنی ۳۳۰۰۰٫ در پایین نحوه پیاده سازی الگو با همین آورده شده است.

کلاس Gift (Component)

Public MustInherit Class Gift

    Public MustOverride Function Cost() As Double

End Class

کلاس Decorator

Public MustInherit Class Decorator

    Inherits Gift

End Class

کلاس Gift1 (ConcreteComponent)

Public Class Gift1

    Inherits Gift

    Public Overrides Function Cost() As Double

        Return 30000

    End Function

End Class

کلاس Gift2 (ConcreteComponent)

Public Class Gift2

    Inherits Gift

    Public Overrides Function Cost() As Double

        Return 10000

    End Function

End Class

کلاس Box1 (ConcreteDecorator )

Public Class Box1

    Inherits Decorator

    Private Gift As Gift

    Public Sub New(ByVal Giftvar As Gift)

        Gift = Giftvar

    End Sub

    Public Overrides Function Cost() As Double

        Return 1000 + Gift.Cost

    End Function

End Class

کلاس Box2 (ConcreteDecorator )

Public Class Box2

    Inherits Decorator

    Private Gift As Gift

    Public Sub New(ByVal Giftvar As Gift)

        Gift = Giftvar

    End Sub

    Public Overrides Function Cost() As Double

        Return 1500 + Gift.Cost()

    End Function

End Class

کلاس Flower (ConcreteDecorator )

Public Class Flower

    Inherits Decorator

    Private Gift As Gift

    Public Sub New(ByVal Giftvar As Gift)

        Gift = Giftvar

    End Sub

    Public Overrides Function Cost() As Double

        Return 2000 + Gift.Cost

    End Function

End Class

ماژول Main

Sub Main()

        Dim Gift1 As Gift = New Gift1()

        Gift1 = New Box1(Gift1)

        Gift1 = New Flower(Gift1)

        System.Console.WriteLine(“Price = “ & Gift1.Cost)

 

        Dim Gift2 As Gift = New Gift2()

        Gift2 = New Box1(Gift1)

        Gift1 = New Flower(Gift1)

        System.Console.WriteLine(“Price = “ & Gift1.Cost)

        Console.ReadLine()

 

    End Sub

 

الگوی Flyweight

تصور کنید، شما مسئول طراحی یک برنامه هستید که قرار است برای هر کارمند یک سازمان، کارت ویزیتی مانند شکل زیر چاپ کند. سازمان مورد نظر، یک سازمان بسیار بزرگ با چند هزار کارمند می باشد.

نام و نام خانوادگی

سمت

نام شرکت

آدرس

اواین طراحی که به ذهن می تواند خطور کند، یک طراحی بسیار ساده است. یک کلاس به نام کارت ویزیت تعریف می کنیم و صفاتی را که در کارت قرار دارند، به کلاس منتقل می کنیم و یک متد چاپ هم برای چاپ کارت تعریف می کنیم.

visitCard

Name

Title

Company

Address

print

در این صورت شما باید به ازاء هر کارمند یک نمونه از کلاس visitCard ایجاد کند، یعنی شما باید چند هزار شی visitCard ایجاد کند. و این می تواند منابع زیادی از سیستم را مصرف کند. ولی شما با توجه به ساختار کارت متوجه می شود که، نام شرکت و آدرس برای تمام افراد یکی است. با این آگاهی، آیا می خواهید تغییری در طراحی خود انجام بدهید یا نه؟

یا شما مسئول طراحی یک برنامه پردازش متن هستید. شکل زیر، می تواند یک نمودار کلاس ساده شده برای این برنامه باشد.

هر نمونه از کلاس Docchar نماینگر یک کاراگتر در سند است. برای تغییر فونت یک کاراگتر می توانیم متد SetFont از شی Docchar فراخوانی کنیم. اگر فونت یک کاراگتر مشخص نشده باشد، از فونت container خود استفاده خواهد کرد.

یک سند نمونه از این برنامه را با طراحی بالا در نظر بگیرید،  یک سند که شامل چندین صفحه است، هر  صفحه شامل چندین شی پارگراف خواهد بود، و هر پارگراف شامل چندین شی LineOfTextad   خواهد بود و آن نیز شامل صد ها شی DocChar خواهد بود، یعنی در یک سند چند صفحه ای ممکن است هزار ها شی  DocChar داشته باشیم که، حافظه زیادی را از سیستم مصرف خواهد کرد. شما برای کاهش مصرف حافظه، طراحی خود را به چه صورت تغییر می دهید؟

یک راه حل کاندید و خوب برای حل هر دو مسئله بالا، الگوی Flyweight است. که به بررسی آن خواهیم پرداخت. مشکل ما در هر دو مسئله بالا، تولید نمونه های بیش از حد از یک کلاس بود که منجر به مصرف زیاد منابع می شد. یک شی شامل ۲ نوع اطلاعات است:

۱-       اطلاعات داخلی (Intrinsic Information) : این نوع اطلاعات، اطلاعاتی هستند که برای تمام نمونه های یک کلاس ثابت است. برای مثال، نام شرکت و آدرس در مثال اول برای تمام کارمندان ثابت است.

۲-       اطلاعات خارجی (Extrinsic Information) : این نوع اطلاعات، اطلاعاتی هستند که از نمونه ای به نمونه ای دیگر فرق می کند، یعنی اشیاء را از همدیگر متمایز می سازد. برای مثال، نام و سمت کارمند در مثال اول.

پیشنهاد الگوی Flyweight این است که،  اطلاعات خارجی را، به خارج از کلاس منتقل کنیم و این اطلاعات را به صورت پارامتر های ورودی متدها دریافت کنیم، و تعداد نمونه ها را با به اشتراک گذاری آنها کاهش دهیم. نمودار کلاس این الگو بصورت زیر است.

در نمودار بالا هر کدام از،ConcreteFlyweight ها نمونه های به اشتراک گذاری یک کلاس هستند. چون اشیاء به اشتراک گذاشته شده اند، Client ها نباید بطور مستقیم نمونه ای از آنرا ایجاد کنند. برای حل این مشکل، کلاس  FlyweightFactory را ایجاد می کنیم. این کلاس باید بداند که آیا نمونه ای از یک کلاس ایجاد شده است یا نه. برای این کار، لیستی از اشیاء ایجاد شده را نگهداری می کنیم  که این اشیاء از کلاس های مختلف توسط یک صفت کلید از هم متمایز می شوند. در مثال ۲ ما برای حل مشکل خود برای هر کاراکتر، یک کلاس،تعریف می کنیم. کلید هر کدام از کلاس ها همان، کاراکتری است که نمایش خواهند داد. برای نمونه کلاس زیر را در نظر بگیرید، کلید هر کلاس را در  یک Hashtable ذخیره می کنیم، و وقتی که Client بخواهد نمونه ای از کلاس مورد نظرش را بسازد، این کلاس بررسی می کند که آیا این کلید در Hashtable وجود دارد یا نه. اگر وجو نداشته باشد، نمونه ای از کلاس مورد نظر ایجاد می کند، در غیر اینصورت  مرجعی (reference) به آنرا برگشت می دهد.

class CharacterFactory

    {

        private Hashtable characters = new Hashtable();

 

        public Character GetCharacter(char key)

        {

            Character character = characters[key] as Character;

            if (character == null)

            {

                switch (key)

                {

                    case ‘A’: character = new CharacterA(); break;

                    case ‘B’: character = new CharacterB(); break;

                    //…

                    case ‘Z’: character = new CharacterZ(); break;

                }

                characters.Add(key, character);

            }

            return character;

        }

    }

 

الگوی Memento

نمی دانم تا بحال پشت کامیوتر خودتان نشستید تا یک مرحله از یک بازی کامپیوتری را به پایان برساند یا نه؟ اما کسانی که اینکار را انجام دادند تصور کنند یک بازی استراتژیک مانند کمانندو ها را بازی می کنند اما بازی بدون قابلیت ذخیره کردن ارائه شده است. در این حالت حتما اکثر افراد این بازی را خیلی زود کنار خواهند گذاشت چون واقعا کار کاربر خیلی سخت خواهد شد. پس اگر روزی قرار باشد یک بازی کامپیوتری را طراحی و پیاده سازی کنیم برای برآورده کردن نیاز های کاربر حتما باید بازی را با قابلیت ذخیره کردن طراحی و پیاده سازی کنیم.

اجازه بدهید یکبار دیگر مسئله را تعریف کنیم: فرضی کنید شما در حال طراحی یک بازی هستید. این بازی باید با قابلیتی  ارائه شود که کاربر در هر قسمتی از بازی خواست بتوانید بازی را در آن نقطه ذخیره کنید و سپس هر زمانی که خواست بتواند بازی را از همان نقطه ای که ذخیره کرده است ادامه دهید. راه حل و طراحی شما برای این مسئله چست و چگونه می تواند باشد؟

یا یک مسئله دیگر: تصور کنید شما در حال طراحی یک فروشگاه الکترونیکی برای یک شرکت هستید. و یکی از ویژگیهای در خواست شده از طرف ذی النفعان سیستم این است که، هنگامیکه یک کاربر وارد فروشگاه می شود و اجناس مورد نیاز خود را به سبد خریدش اضافه می کند، اما قبل از اینکه سفارش خود را تائید کند از فروشگاه خارج می شود. سیستم باید قابلیت  این را داشت باشد که هنگام ورود بعدی همان کاربر، آیتم های موجود در سبد خرید قبلی را بازیابی کند و در سبد خرید مشتری قراد دهد.

در هر دو مسئله بالا، کار ما ذخیره حالت موجود اشیاء و سپس بازیابی آن حالت در صورت نیاز هست. یک راه حل موجود و خوب برای مسائل بالا و شبیه آنها، الگوی Memento است. که نحوه عملکرد آنرا، برسی خواهیم کرد.

نمودار UML، این الگو بصورت زیر است:

همانطوریکه در بالا اشاره شد، ما نیاز داریم تا حالت یک شی را ذخیره و بازیابی کنیم، این شی با نام originator در این الگو مشخص می شود. اما نحوه ذخیره کردن وضعیت شی موجود به این صورت است که زمانیکه برنامه Client درخواست ذ   خیره کردن را از شی originator می کند. این شی (originator)، تمام صفاتی را که برای بازیابی حالتش نیاز است را، در یک شی دیگر به نام Memento قرار می دهد و آن را به Client ازسال میکند (در نمودار مقدار صفت state از شی originator، در مقدار صفت stateشی Memento قرار می گیرد.). ما نیاز داریم تا اشیاء از نوع Memento را، نگهداری و مدیریت کنیم. برای اینکار از کلاسی به نام caretaker، استفاده می کنیم. زمانیکه یک شی Mementoایجاد می شود، آن شی به مجموعه اشیاء Caretaker اضافه می شود. وقتی که یک عمل undo انجام می شود شی Caretaker با یک شی دیگر (client)، همکاری می کند تا یک شی Memento انتخاب شود. بعد از انتخاب شی Memento ، آن شی متد setMemento شی Originator را فراخوانی می کند تا حالت انتخاب شده را بازیابی کند.

فرضی کنید شما در حال طراحی یک برنامه ویرایشگر متن هستید، و یکی از نیازهای مطرح شده توسط کاربران این مورد است که وقتی آنها قسمتی از یک متن را کپی می کنند، آن قسمت به یک لیست اضافه شود و نمایش داده شود. سپس زمانیکه کاربر به یکی از متن های کپی شده نیاز داشت، یکی از آنها از لیست انتخاب کند تا متن انتخاب شده به متن اصلی اضافه شود(عمل paste). دقیقا چیز شبیه clipboard برنامه Microsoft Office Word.

می خواهیم این خواسته را توسط الگوی Memento، طراحی کنیم. در این مثال شی که ما نیاز داریم، حالتش را ذخیره کنیم و سپس در صورت نیاز بازیابی کنیم، شی Clipboard است.

کلاس originator که کد مربوط به Clipboard را پیاده سازی می کند. صفت _Clipboard ، بیانگر حالت این شی است و برای بازیابی آن باید این صفت را ذخیره کنیم.

Public Class originator

Private _Clipboard As String

Public Property Clipboard() As String

Get

Return _Clipboard

End Get

Set(ByVal value As String)

_Clipboard = value

End Set

End Property

Public Function createMemento() As memento

Return New memento(_Clipboard)

End Function

Public Sub setMemento(ByVal _memento As memento)

_Clipboard = _memento.Clipboard

End Sub

End Class

کلاس memento که برای ذخیره اطلاعات مورد نیاز برای یازیابی حالت یک نمونه از شی originator به کار می رود.

Public Class memento

Private _Clipboard As String

Public Sub New(ByVal Data As String)

_Clipboard = Data

End Sub

Public Property Clipboard() As String

Get

Return _Clipboard

End Get

Set(ByVal value As String)

_Clipboard = value

End Set

End Property

End Class

کلاس caretaker برای نگهداری نمونه های مختلفی از کلاس memento به کار می رود. در ا ینجا برای نگهداری این نمونه ها از ArrayList استفاد شده است. تو سط متد list، مجموعه اشیایی memento برای نمایش به کاربر برگشت داده می شود. تا کاربر یکی از آنها را در صورت نیاز انتخاب کند.

Public Class caretaker

Private memento As New ArrayList

Public Sub Add(ByVal _memento As memento)

memento.Add(_memento)

End Sub

Public Function List() As ArrayList

Return memento

End Function

End Class

برای تست کلاس های بالا از یک فرم به نام FrmTest استفاده شده است. که یک کنترل ListBox بر روی آن قرار دارد تا مقادیر موجود در هر کدام از نمونه های شی memento را نمایش دهد. تا کاربر بتواند حالت مورد نیاز خود را از میان آنها انتخاب کند.

Public Class FrmTest

Dim Ins As New originator

Dim List As New caretaker

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

Ins.Clipboard = “Ali”

List.Add(Ins.createMemento())

Ins.Clipboard = “asd”

List.Add(Ins.createMemento())

Ins.Clipboard = “sdf”

List.Add(Ins.createMemento())

Me.ListBox1.DataSource = List.List

Me.ListBox1.DisplayMember = “Clipboard”

End Sub

Private Sub ListBox1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles ListBox1.Click

Ins.setMemento(List.List(Me.ListBox1.SelectedIndex))

End Sub

End Class

توجه:  در پیاده سازی مثال بالا، بعضی از قوانین شی گرایی نادیده گرفته شده است.(تصحیح به عهده دوستان)

Observer Pattern

۲۶ اردیبهشت ۱۳۸۶ ۳ دیدگاه

شاید شما هم زمانیکه تلویزیون را باز می کنید، یا وارد اینترنت می شود، یکراست به سراغ شبکه ها یا سایت های خبری می رود، تا از اتفاقات و رویدادهای مورد علاقه خود آگاه شود. حتی بعضی وقت ها این خبرها و رویدادها باعث می شوند شما روند کاری خود را تغییر دهید. حتی بعضی از خبرها در موضوعات خاص برای شما آنقدر اهمیت دارد که، عضو یک سایت خبری می شود تا هر زمانیکه خبر جدیدی  وجود داشته باشد، به ایمیل شما نیز ارسال شود. بنابراین هر زمانیکه یک خبر جدید به سایت اضافه می شود، آن خبر به ایمیل شما نیز ارسال می شود. تا زمانیکه شما از عضویت در آن سایت انصراف ندادید، همه خبرهای جدید به شما ارسال می شود، و زمانیکه شما از عضویت خود انصراف دادید، خبرهای جدید به شما ارسال نخواهد شد ولی برای اعضاء دیگر سایت ارسال خواهد شد. اگر شما مسئول طراحی این سیستم بودید، چگونه عمل می کردید؟

یک مرکز کاریابی را در نظر بگیرید، افراد مختلفی با تخصص های مختلف، به این مرکز مراجعه می کنند، و با توجه به تخصص هایشان برای درخواست کار ثبت نام می کنند. هر زمانیکه درخواست نیرو توسط یک شرکت در یک تخصص خاص از آن مرکز شد. آن مرکز  افرادی را که در آن تخصص ثبت نام کرده اند، از آن موقعیت کاری مطلع می کنند. اگر قرار باشد شما یک سیستم نرم افزاری برای این کار طراحی کنید، طراحی شما به چه صورت خواهد بود؟

هر کدام از ما می توانیم نسبت به درک خود از مسئله و سلیقه کاری، طراح های مختلفی برای این مسئله ارائه دهیم. اما یک طراحی که می تواند یک جواب خوب و عالی باشد، الگوی Observer  است که توانسته است بارها و بارها به این مسئله پاسخ بدهد.

در هر دو مسئله بالا، ما یک شی داریم که مجموعه ای از اشیاء به آن وابسته هستند. هر زمانی که وضعیت شی مورد نظر تغییر می کند، اشیاء دیگر از آن تغییر آگاه می شوند. در این الگو، مجموعه اشیاء وابسته را Observer   های می نامیم و شی را که دیگر اشیاء به آن وابسته هستند را Subject می نامیم. برای نمونه در مثال اول، افرادی که در سایت عضو می شوند یک شی Observer   هستند. و شی خبر، همان  Subject  هست.

الگوی Observer  یک وابستگی،  یک به چند بین اشیاء هست، هنگامیکه شی طرف یک، وضعیتش تغییر کند، اشیاء وابسته مطلع می شوند و وضعیت خودشان را با توجه به آن وضعیت بروز رسانی می کنند.

مکانیزم عملکرد این الگو بصورت زیر است:

۱-       Subject باید یک اینترفیس برای ثبت (registering) و انصراف از عضویت (unregistering) و اطلاع از تغییرات را آماده کند.

۲-       Subject باید اطلاعات حالتی را که، observer ها برای آن ریجستر شده اند را به observer  ها ارسال کند.

۳-       Observer  باید یک اینترفیس برای دریافت پیام از Subject آماده کند.

نمودار کلاس این الگو بصورت زیر است:

 

 

با یک مثال دیگر کار را ادامه می دهیم. فرض کنید که در اداره شما ، در داده های پایگاه داده مرکزی تغییرات غیر مجازی، داده شده است. برای حل این مشکل مدیران پیشنهاد کرده اند که هر تغییری که در پایگاه داده می شود، باید توسط یک پیام، به افراد مشخص شده ای اعلام شود. شما برای حل این مشکل، الگوی Observer  را در نظر می گیرید. دقیقا بر طبق نمودار عمل می کنیم و با یک حالت فرض این مثال را پیاده سازی می کنیم.

 

اینترفیس مربوط به subject

Public Interface subject

    Sub Attach(ByVal Ins As Observer)

    Sub Detach(ByVal Ins As Observer)

    Sub Notify()

End Interface

اینترفیس مربوط به Observer  

Public Interface Observer

    Sub Update(ByVal operation As String, ByVal record As String)

End Interface

کلاس database که اینترفیس مربوط به subject را پیاده سازی می کند.

Public Class dataBase

    Implements subject

    Private observers As ArrayList

    Private operation As String

    Private record As String

 

    Public Sub New()

        observers = New ArrayList

    End Sub

 

    Public Sub Attach(ByVal Ins As Observer) Implements subject.Attach

        observers.Add(Ins)

    End Sub

 

    Public Sub Detach(ByVal Ins As Observer) Implements subject.Detach

        observers.Remove(observers)

    End Sub

 

    Private Sub Notify() Implements subject.Notify

        For I As Integer = 0 To observers.Count – ۱

            Dim Ins As Observer = observers(i)

            Ins.Update(operation, record)

        Next

    End Sub

    Public Sub editDatabase(ByVal ope As String, ByVal rec As String)

        Me.operation = ope

        Me.record = rec

        Notify()

    End Sub

 

End Class

کلاس Archiver که اینترفیس Observer   را پیاده سازی می کند.

Public Class Archiver

    Implements Observer

    Public Sub Update(ByVal operation As String, ByVal record As String) Implements Observer.Update

        MessageBox.Show(“The archiver says a “ + operation + ” operation was performed on “ + record)

    End Sub

End Class

کلاس boss که اینترفیس Observer   را پیاده سازی می کند.

Public Class Boss

    Implements Observer

    Public Sub Update(ByVal operation As String, ByVal record As String) Implements Observer.Update

        MessageBox.Show(“The boss says a “ + operation + ” operation was performed on “ + record)

    End Sub

End Class

 

کلاس client که اینترفیس Observer   را پیاده سازی می کند.

Public Class client

    Implements Observer

    Public Sub Update(ByVal operation As String, ByVal record As String) Implements Observer.Update

        MessageBox.Show(“The client says a “ + operation + ” operation was performed on “ + record)

    End Sub

End Class

 

تست

Dim DB As New dataBase

Dim Ar As New Archiver

Dim Bo As New Boss

Dim Cl As New client

DB.Attach(Ar)

DB.Attach(Bo)

DB.Attach(Cl)

DB.editDatabase(“Delete”, “Record 1″)

در مثال بالا، ما سه نوع Observer   داریم. که هر وقت تغییری در پایگاه داده اعمال می شود، با یک پیام به آنها اعلام می شود.