بایگانی

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

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

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

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

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

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

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

 

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

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

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

 

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

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

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

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

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

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

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

الگوی Mediator

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

 

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

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

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

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

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

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

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

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

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

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

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

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

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

الگوی استراتژی (Strategy Pattern)

۳۱ فروردین ۱۳۸۶ ۴ دیدگاه

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

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

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

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

الگوی استراتژی گزینه مناسبی برای مسائلی است که می توانند از چندین الگوریتم مختلف به مقصود خود برسند.

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

 

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

۱

Shell Sort

۲

Quick Sort

۳

Merge Sort

ما برای مرتب سازی در این برنامه دارای سه استراتژی هستیم. که هر کدام را به عنوان یک کلاس جداگانه در نظر می گیریم (همان کلاس های ConcreteStrategy). برای اینکه کلاس Client  بتواند به سادگی یک از استراتژی ها را انتخاب کنید بهتر است که تمام کلاس های استراتزی دارای اینترفیس مشترک باشند. برای این کار می توانیم یک کلاس abstract تعریف کنیم و ویژگیهای مشترک کلاس های استراتژی را در آن قرار دهیم و کلاس های استراتژی آنها را به ارث ببرند(همان کلاس Strategy) و پیاده سازی کنند.

کلاس abstract که کلاس های استراتژی آنرا به ارث می برند.

abstract class SortStrategy

    {

        public abstract void Sort(ArrayList list);

    }

 

کلاس مربوط به QuickSort

class QuickSort : SortStrategy

    {

        public override void Sort(ArrayList list)

        {

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

        }

    }

 

کلاس مربوط به ShellSort

    class ShellSort : SortStrategy

    {

        public override void Sort(ArrayList list)

        {

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

        }

    }

 

کلاس مربوط به MergeSort

    class MergeSort : SortStrategy

    {

        public override void Sort(ArrayList list)

        {

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

        }

    }

 

کلاس Context که یکی از استراتزیها را برای مرتب کردن لیست به کار می برد.

    class SortedList

    {

        private ArrayList list = new ArrayList();

        private SortStrategy sortstrategy;

 

        public void SetSortStrategy(SortStrategy sortstrategy)

        {

            this.sortstrategy = sortstrategy;

        }

 

        public void Add(string name)

        {

            list.Add(name);

        }

 

        public void Sort()

        {

            sortstrategy.Sort(list);

        }

    }

 

  

الگوی Template method

۱۴ فروردین ۱۳۸۶ ۳ دیدگاه

 

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

دستوالعمل ساخت قهوه:

۱٫       مقداری آب را می جوشانید.

۲٫       مقدار قهوه در آب جوشانده شده می ریزد تا دم بکشد.

۳٫       فهوه را در فنجان می ریزد.

۴٫       مقداری شکر و یا شیر به آن اضافه می کنید.

دستورالعمل ساخت چای:

۱٫       مقداری آب را می جوشانید.

۲٫       مقدار چای خشک در آب جوشانده شده می ریزد تا دم بکشد.

۳٫       چای را در فنجان می ریزد.

 

۴٫       مقداری شکر به آن اضافه می کنید.

 

 

اگر بخواهیم برنامه ای برای تهیه چای و قهوه بنویسیم کلاس های را به صورت زیر خواهیم داشت.

 

کلاس قهوه

Public Class Coffee

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

    Public Sub prepareRecipe()

        مراحل تهیه قهوه

        boilWater()

        brewCoffeeGrinds()

        pourInCup()

        addSugereAndMilk()

    End Sub

    Public Sub boilWater()

        Console.WriteLine(جوشاندن آب)

    End Sub

    Public Sub brewCoffeeGrinds()

        Console.WriteLine(ریختن پودر قهوه به داخل آب جوشانده شده)

    End Sub

    Public Sub pourInCup()

        Console.WriteLine(ریختن قهوه به فنجان)

    End Sub

    Public Sub addSugereAndMilk()

        Console.WriteLine(اضافه کردن شیر و شکر)

    End Sub

End Class

 

 

کلاس چای

Public Class Tea

    Public Sub prepareRecipe()

        boilWater()

        brewTea()

        pourInCup()

        addSugere()

    End Sub

    Public Sub boilWater()

        Console.WriteLine(جوشاندن آب)

    End Sub

    Public Sub brewTea()

        Console.WriteLine(ریختن چای به داخل آب جوشانده شده)

    End Sub

    Public Sub pourInCup()

        Console.WriteLine(ریختن چای به فنجان)

    End Sub

    Public Sub addSugere()

        Console.WriteLine(اضافه کردن شکر)

    End Sub

End Class

 

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

طراحی بالا یک طراحی خوب است اما نمی شود طراحی را بهتر از این کرد؟   اگر توجه کنیم متوجه می شویم که برای تهیه هر دو مورد الگوریتم یکسانی را به کار می بریم:

۱٫       جوشاندن آبی

۲٫       اضافه کردن چای یا قهوه به آب جوشیده شده

۳٫       ریختن نوشیدنی به دست امده در فنجان

۴٫       اضافه کردن چاشنی مورد نظر به نوشیدنی

پس ما می توانیم با کمی تغییرات متد prepareRecipe را در کلاس پایه پیاده سازی کنیم.

 Public Sub prepareRecipe()

        boilWater()

        brewTea()

        pourInCup()

        addSugere()

 End Sub

 

Public Sub prepareRecipe()

        boilWater()

        brewCoffeeGrinds()

        pourInCup()

        addSugereAndMilk()

End Sub

 

 همانطوریکه می توانید مشاهده کنید کلاس مر بوط به قهوه متدهای به نام brewCoffeeGrinds و addSugereAndMilk را استفاده می کند در حالیکه کلاس مربوط به چای از متد های به نام brewTea و addSugere استفاده می کند. یک راه حل این است که برای هر مرحله غیر مشابه یک نام مشترک در نظر بگیریم. نام متدهای brewTea و brewCoffeeGrinds را به brew تغییر دهیم. و نام متدهای addSugereAndMilk و addSugere را به addCondiments  تغییر می دهیم. پس متد prepareRecipe برای هر دو کلاس به صورت زیر تغییر می کند.

Public Sub prepareRecipe()

        boilWater()

        brew ()

        pourInCup()

        addCondiments()

End Sub

 

 پس حالا می توانیم این متد را بطور کامل به کلاس پایه منتقل کنیم و طراحی را به صورت زیر تغییر دهیم.

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

الگوی Template method، مراحل انجام یک الگوریتم را در یک متد در کلاس پایه تعریف می کند و اجازه می دهد زیر کلاس ها یک یا چند مرحله از الگوریتم را پیاده سازی کنند. در واقع اسکلت یک الگوریتم در یک متد تعریف می شود.

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

نمودار UML :

نمودار UML این الگو به صورت بالا است. که در آن کلاس AbstractClass یک کلاس Abstract  است. که الگوی قالب در آن تعریف می شود. و متد primitiveOperation یک متد Abstract  است (یک مرحله از الگوریتم) که در زیر کلاس پیاده سازی خواهد شد. همانطوریکه در مثال بالا مشاهده کردیم می تواند بیش از یک کلاس ConcerteClass وجود داشته باشد. این حالت زمانی رخ می دهد که بعضی از مراحل الگوریتم بتواند در روش های مختلف پیاده سازی شود.

 

الگوی زنجیره مسئولیت (Chain of Responsibility pattern)

یک سرویس دهنده اینترنتی را در نظر بگیرید. این شرکت دارای سه سطح پشتیبانی به شرح زیر برای کاربران است:

سطح ۱: در این سطح به مشکلات ابتدایی کاربران مانند فراموش کردن کلمه عبور کاربران و … رسیدگی می شود.

سطح ۲: اگر اعضای گروه سطح ۱ نتوانند مشکل مورد نظر را حل کنند. مشکل برای حل به گروه سطح ۲ ارجاع داده می شود.

سطح ۳: اگر اعضای گروه ۲ نیز نتوانند مشکل مورد نظر را حل کنند.مشکل برای حل به گروه سطح ۳ ارجاع داده می شود. در این سطح برای حل مشکل یک قرار ملاقات در محل مشکل با مشتری گذاشته می شود.

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

مثالی که در بالا ارائه شده تقریبا تعریفی از الگوی Chain of responsibility (زنجیره مسئولیت) می باشد.

در این الگو به یک شی اجازه داده می شود در خواستی را ارسال کند بدون اینکه بداند کدام شی یا اشیاء آنرا دریافت خواهند کرد و به آن پاسخ خواهند داد. این کار با ارسال درخواست به زنجیره ای از اشیاء صورت می گیرد. هر شی در این زنجیره می تواند به درخواست ارائه شده پاسخ دهد یا آن را به شی بعدی در زنجیره ارسال کند. در واقع هر شی در زنجیره بعنوان یک پاسخگو برای درخواست ارائه شده عمل می کند . اگر شی مورد نظر بتواند درخواست راجواب دهد، پاسخ آن را می دهددر غیر اینصورت آن را به شی جانشین اش (شی بعدی در زنجیره) ارسال می کند.

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

سطوح مدیریت

مبلغ سفارش

مدیر نمایندگی

۲۵۰۰۰

مدیر ناحیه

۱۰۰۰۰۰

نایب‌ رئیس‌

۲۰۰۰۰۰

رئیس‌

۴۰۰۰۰۰

 

شما برای اینکار چه الگوی را پیشنهاد می کنید؟

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

سپس یک کلاس انتزاعی به نام مدیریت سفارش تعریف می کنیم که دارای یک اینترفیس مشترک برای هر کدام از سطوح مدیریت است. که نمودار کلاس  مربوط به مدیریت سفارش و سطوح مدیریت به صورت زیر خواهد بود. که متد تعیین شی جانشین (SetSuccessor)، برای مشخص کردن شی بعدی (شی جانشین) در زنجیره عمل می کند.

برای تائید یک سفارش، کارهای زیر صورت خواهد گرفت:

۱٫    ایجاد یک مجموعه از اشیای که می توانند به درخواست های رسیده شده پاسخ بدهند (سطوح مدیریت). و قرار دادن آنها در یک زنجیره به طور مرتب بر حسب مقادیری که می توانند تائید کنند. هر یک از این اشیاء توسط متد SetSuccessor به شی بعدی متصل می شود.(کلاس Main)

۲٫       یک درخواست تائید به اولین شی موجود در زنجیره ارسال می شود که این کار توسط فراخوانی متد   authorize  آن شی انجام می شود. اگر مبلغ سفارش از مقدار مبلغی که ان شی نی تواند تائید کند کوچکتر باشد، آنرا تائید می کند در غیر اینصورت آن درخواست را به شی بعدی در زنجیره ارسال می کند. (برای مثال در کد زیر می توانید کلاس BranchManager را بررسی کنید. ) 

کلاس مدیریت سفارش

abstract class RHandler

    {                                     

        protected RHandler successor;

 

        public void SetSuccessor(RHandler successor)

        {

            //تعیین شی جانشین

            this.successor = successor;

        }

 

        public abstract void authorize (PurchaseRequest purchase);

    }

کلاس مدیر نمایندگی

 

class BranchManager: RHandler
{

 public override void authorize (PurchaseRequest purchase)
{
   // تائید سفارش

      if (purchase.Amount <=25000)
{

       

      }
else if (successor != null)
{
successor.ProcessRequest(
RegionalDirector);
}
}
}

کلاس Main

class MainApp

    {

        static void Main()

        {

            BranchManager A = new BranchManager();

            RegionalDirector B = new RegionalDirector();

            VicePresident C = new VicePresident();

            President D = new President();

            A.SetSuccessor(B);

            B.SetSuccessor(C);

            C.SetSuccessor(D);

 

            Purchase p = new Purchase( 1, “Order 1″,15000);

            A.authorize(p);

 

            Purchase p = new Purchase( 2, “Order 2″,110000);

            A.authorize(p);

        }

    }

 

 

 

دیاگرام کلاس الگو: