وارد فروشگاه می شوید، غرفه ها را یکی یکی نگاه می کنید، بدنبال یک هدیه مناسب برای یک شخص خاص هستید. با زحمت و وسواس زیاد آنرا انتخاب می کنید و به فروشنده تحویل می دهید و می گوید آنرا برایتان کادو و تزئین کند. فروشنده جعبه های تزیئنی مختلف را برای قرار دادن هدیه برای شما نشان می دهد تا یکی از آنها را انتخاب کنید. شما جعبه مورد نظر را انتخاب می کنید. و پیشنهاد می کنید در صورت امکان بعد از قرار دادن هدیه شما و پیچیدن آن در کاغذ کادو، یک شاخه کل روی آن بچسباند. کار تمام می شود. فروشنده می گوید قیمت هدیه ای که انتخاب کرده اید، X تومان است، قیمت جعبه Y تومان است و فیمت شاخه گل Z تومان است. شما باید سر جمع X+Y+Z تومان را پرداخت کنید.
حالا فرض کنید شما خرید، خود را تمام کردید و هدیه را به شخص مورد نظر خود تقدیم کردید. اما از طرف مسئولین همین فروشگاه، شرکت شما برای طراحی سیستم سفارش فروشگاه در نظر گرفته شده است. این فرشگاه دارای کالاهای متعدد کادویی هست و همچنین دارای انواع زیادی از جعبه های تزئینی و وسایل برای تزئین کالاهای مختلف است. سیستم باید قابلیت این را داشته باشدکه قیمت کل را برای یک کالا با سایر وسایل تزئینی محاسبه کند. طراحی شما برای این مسئله به چه صورت می تواند باشد؟
یک طراحی برای این مسئله می تواند به صورت زیر باشد: یعنی به این صورت عمل شود که، اگر مشتری، یک هدیه را بدون هیچ کالای تزئینی دیگر خرید، یک نمونه از خود آن کلاس ایجاد شود و قیمت آن، توسط متد قیمت برگشت داده شود. اگر یک هدیه نوع 1با جعبه 1 خریداری شود، نمونه ای از هدیه نوع 1 با جعبه نوع 1 ایجاد شود، و قیمت کل خرید برگشت داده شود.
اما در این حالت، اگر فروشگاه دارای دهها هدیه و جعبه مختلف باشد، و شما هر کدام از ترکیب های ممکن را بصورت یک کلاس جداگانه تعریف کنید، برای یک کار ساده شاید صدها کلاس داشته باشید که، بی شک مدیریت و تغییر در هر کدام از کلاس ها، هزینه زیادی را در بر خواهد داشت.
در حال طراحی اینترفیس (UI) برنامه هستید، ترجیح می دهید که اطراف بعضی از دکمه ها (button) یک نوار رنگی نازک باشد. اما دکمه های که شما استفاده کرده اید، این قابلیت را ندارد. می خواهید خودتان این قابلیت را به دکمه ها اضافه کنید. شما این کار را به چه روشی انجام می دهید؟
طراحی های مختلفی را می توان برای هر دو مسئله بالا ارائه داد. اما یک طراحی و راه حل خوب الگوی Decorator است.
در هر دو مثال بالا، ما می خواهیم یک رفتار جدید را به یکی شی اضافه کنیم. ولی می خواهیم بدون استفاده از وراثت این رفتار را به شی اضافه کنیم. این الگو اجازه می دهد، تا یک رفتار را بدون استفاده از وراثت و بصورت دینامیک به یک شی اضافه کنیم. نمودار کلاس این الگو بصورت زیر است:
شیی که می خواهیم رفتار جدیدی را به آن اضافه کنیم، همان ConcreteComponent، در نمودار بالا می باشد (شی دکمه در مثال دوم). و شیی که رفتار جدید را به شی ConcreteComponent، اضافه می کند. یکی از ConcreteDecorator ها، خواهد بود (نوار نازک در مثال دوم ). اما این رفتار جدید، چگونه اضافه می شود؟ دقیقا به همان صورتیکه ما هدیه را در داخل جعبه قرار دادم. اینجا نیز یک نمونه از کلاس مورد نظر را در داخل کلاس دیگر قرار می دهیم و اجازه می دهیم کلاس در برگیرنده بر روی آن کار کند. در پایین با مثال اول به بررسی کامل عملکرد این الگو خواهیم پرداخت.
در مثال اول، شما یک هدیه، یک جعبه و یک گل می خرید. فرضی کنید می خواهیم، مقدار کل را با الگوی Decorator محاسبه کنیم:
در ابتدا یک شیی از کلاس هدیه 1 ایجاد می کنیم. این کلاس یک متد به نام قیمت برای محاسبه قیمت خود دارد.
سپس مشتری یک جعبه را انتخاب کرده بود، و فروشنده هدیه را در داخل آن قرار داده بود. پس ما نیز همین کار را می کنیم، یعنی فرضا نمونه ای از جعبه 1 را ایجاد می کنیم و شی هدیه ایجاد شده را در داخل آن قرار می دهیم. و هدیه را با جعبه تزئین می کنیم.
در آخر مشتری خواسته بود، یک گل بر روی هدیه نصب شود. ما نیز همین کار را می کنیم، یک نمونه از گل ایجاد می کنیم. و هدیه را با آن تزئین می کنیم.
حل مشتری مبلغ پرداختی را از فروشنده می پرسد. پس ما باید در این نقطه قیمت را محاسبه کنیم. در ابتدا ما متد قیمت را از بیرونی ترین، تزئین کننده فراخوانی می کنیم. یعنی در ابتدا متد قیمت را برای شی گل فراخوانی می کنیم. این شی قیمت شی بعدی یعنی جعبه را فراخوانی می کند. و جعبه متد قیمت، هدیه اصلی را فراخوانی می کند. در این نقطه چون هدیه یک شی تزئین کننده نیست (بلکه یک شی ConcreteComponent است). قیمت خود را برگشت می دهد یعنی 30000. سپس جعبه قیمت خود را به قیمت برگشت داده شده توسط هدیه، اضافه می کند. و مجموع را برگشت می دهدیعنی 31000. در آخر نیز گل مقدار خود را به مقدار برگشت داده شده اضافه می کند و مجموع کل را برگشت می دهد یعنی 33000. در پایین نحوه پیاده سازی الگو با همین آورده شده است.
کلاس 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
|