الگوی 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

 

  1. ۲۱ خرداد ۱۳۸۶ در ۱۴:۰۹ | #1
  2. ۲۱ خرداد ۱۳۸۶ در ۱۵:۵۶ | #2

    با سلام خدمت شما دوست عزیزبرای بخشهای مختلف یک سایت در حال پذیرش مدیر هستیماخبار ماهواره موبایل بخش آزاد سینما عکاسی خودرو تجارت پزشکی ورزش موسیقی کامپیوترهنر و …دوستانی که آماده همکاری هستند و در زمینه های مختلف به صورت تخصصی فعالیت دارند در قسمت نظرات سایت سوابق و تخصص خود – سایتهایی که مدیر هستند و آی دی های خود در سایت ها – بخش مورد نظر برای فعالیت – و هر آنچه ر ا که لازم میدانند ذکر کنندسرپرست کل سایت ***http://modirsite.blogfa.comمتشکرم.

  3. ساناز
    ۲۴ خرداد ۱۳۸۶ در ۱۸:۳۰ | #3

    سلامیه خواهشی ازتون داشتممن یه پروژه تحلیل سیستم با رشنال رز می خوامشما دارید؟اگه دارید میشه واسه من میل کنید واقعا ازتون ممنون میشم

  4. ۲۷ خرداد ۱۳۸۶ در ۱۲:۰۲ | #4

    سلاممنم همون خواهش الناز رو دارم اخرین مهلتم ۱۰تیره که به استاد تحویل بدم وبلاگتونو کلا خوندم وچیزهای جالبی یاد گرفتم استادمون بدون هیچ توضیحی از ما پروژه می خواد اگه می شه به ایمیلم بفرستید خیلی خیلی ممنون می شم هرچی بود چون یه نمونه می خوام تا به وسیله اون بتونم سیستم یه کافینت رو طراحی کنم اگه بفرستید habibeh000@yahoo.com

  5. ۳۰ خرداد ۱۳۸۶ در ۲۰:۳۸ | #5

    سلامممنون از لینک.

  6. ۴ تیر ۱۳۸۶ در ۲۲:۴۹ | #6

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

  7. ۵ تیر ۱۳۸۶ در ۱۹:۵۴ | #7

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

  8. lمجید
    ۵ تیر ۱۳۸۶ در ۲۰:۲۹ | #8

    سلام بابت مطالب بسیار جالبی که دد وبلاگ می گذارید ممنونمبا تشکر

  9. آرش
    ۱۲ تیر ۱۳۸۶ در ۱۰:۲۸ | #9

    با سلام بنده درمورد کاربرد شی گرایی اشکال اساسی دارم از آنجایی که برنامه های کاربردی از rdb بانک اطلاعاتی رابطه ای استفاده می کنند وقیمت ها و اجناس درآن ذخیره میشوند و اشیا هم ثابت نیستند آیا بهترنیست از رویکرد ساختیافته استفاده کنیم

  1. ۱۱ بهمن ۱۳۹۳ در ۰۴:۳۱ | #1