سلام کاربران عزیز ، حال شما که خوبه ؟ امیدوارم که شاد و سلامت با اموزشهای ما که در مورد دیزاین پترن هست همراه بمانید . امروز میخوام در مورد Decorator اموزش بدیم امیدوارم که برایتان مفید واقع شود.
در صورتی که مقالات قبلی را مطالعه نکرده اید، از طریق تاپیک های زیر قابل دسترس هستند:
· Design Patterns
· Singleton Pattern
· Simple Factory Pattern
· Abstract Factory Pattern
· Factory Method Pattern
· Prototype Pattern
· Builder Pattern
· Façade Pattern
· Adapter Pattern
در ادامه مبحث الگوهای طراحی، در این مقاله با یکی دیگر از این الگو ها با نام Decorator آشنا خواهیم شد. بر اساس تعریف GOF “با استفاده از این الگو به صورت پویا، یکسری مسئولیت های اضافی به یک شی واگذار می شود. Decoratorها یک جایگزین انعطاف پذیر برای یک subclass هستند تا به این ترتیب قابلیت توسعه پذیری را ارتقاء دهند”.
اگر بخواهیم به صورت پویا یک مسئولیت یا قابلیت را به هر شی ای واگذار کنیم، به جای Subclass کردن، می توان از الگوی Decorator استفاده کرد. اگر چه Subclass کردن یک روش معمول برای مدیریت رفتارهای اضافه شده است، اما زمانی که تعداد این subclass ها افزایش پیدا کنند، مدیریت و نگهداری از آنها خیلی سخت خواهد شد. از طرفی با استفاده از الگوی Decorator نه تنها چندین subclass، بلکه ترکیبی از آنها را نیز می توان مدیریت کرد.
الگوی Decorator مبتنی بر اصل Open-Closed، یکی از اصول SOLID، است. بعداً بیشتر با SOLID آشنا خواهیم شد. به طور خلاصه اصل Open-Closed پیشنهاد میکند کلاس ها برای توسعه باید باز و برای اصلاح باید بسته شوند.
نحوه عملکرد الگوی Decorator
در الگوی Decorator چهار عنصر کلیدی به شرح زیر وجود دارد:
· Component: اینترفیس شی ای است که می خواهیم یک رفتار پویا را به آن اضافه کنیم.
· ConcreteComponent: پیاده سازی Component
· Decorator: معمولاً یک کلاس abstract است که رفتار پویا را تعریف می کند. همچنین Component را پیاده سازی می کند.
· ConcreteDecorator: پیاده سازی Decorator. هر قابلیت پویایی ConcreateDecorator خودش را پیاده سازی می کند.
با یک مثال ساده شروع میکنیم. ابتدا، مانند مثال وسیله نقلیه مقاله قبل، Component را ایجاد میکنیم:
///
/// The component
///
public interface IVehicle
{
string GetBrand();
string GetModel();
int GetPrice();
}
باید کلاس های ConcreateComponent را نیز تعریف کنیم. دراینجا دو subclass برای این منظور ایجاد کرده ایم.
///
/// The concrete component
///
public class MarutiCar : IVehicle
{
public string GetBrand()
{
return “Maruti”;
}
public string GetModel()
{
return “Swift VXI”;
}
public int GetPrice()
{
return 610000;
}
}
///
/// The concrete component
///
public class HyundaiCar : IVehicle
{
public string GetBrand()
{
return “Hyundai”;
}
public string GetModel()
{
return “Grand i10 Magna”;
}
public int GetPrice()
{
return 540000;
}
}
حالا وقت آن رسیده است که کلاس Decorator را تعریف کنیم. با استفاده از این کلاس، اینترفیس Component پیاده سازی می شود و برای رفتارهای پویا، به عنوان یک کلاس base عمل میکند.
///
/// The Decorator abstract class
///
public abstract class VehicleDecorator : IVehicle
{
private IVehicle _vehicle;
protected VehicleDecorator(IVehicle vehicle)
{
_vehicle = vehicle;
}
public string GetBrand()
{
return _vehicle.GetBrand();
}
public string GetModel()
{
return _vehicle.GetModel();
}
public int GetPrice()
{
return _vehicle.GetPrice();
}
}
سپس باید کلاس هایConcreteDecorator را طراحی کنید تا رفتار پویا را مدیریت کند.
public class DiwaliOffer: VehicleDecorator
{
public DiwaliOffer(IVehicle vehicle): base(vehicle) {}
public int PercentDiscount = 20;
public int NewPrice()
{
return base.GetPrice() * (100 – PercentDiscount) / 100;
}
}
public class HoliOffer: VehicleDecorator
{
publi cHoliOffer(IVehicle vehicle): base(vehicle) {}
public int PercentDiscount = 15;
public int NewPrice()
{
return base.GetPrice() * (100 – PercentDiscount) / 100;
}
}
همانطور که متوجه شده اید، دو کلاس پویا اضافه کردیم تا پیشنهادات Diwali و Holi را مدیریت کند. حتی می توان برای مدیریت چنین مواردی، چندین کلاس تعریف کرد.
اجازه دهید ببینیم چطور در عمل client از این تنظیمات استفاده میکند.
Console.Title = “Decorator pattern demo”;
MarutiCar mCar = new MarutiCar();
Console.WriteLine(“{0} {1} Regular price: {2}”, mCar.GetBrand(), mCar.GetModel(), mCar.GetPrice());
//Diwali Offer
Diwali OfferdOffer = newDiwaliOffer(mCar);
Console.WriteLine(“{0} {1} Diwali price: {2} after discount of {3} percent”, mCar.GetBrand(), mCar.GetModel(), dOffer.NewPrice(), dOffer.PercentDiscount);
//Holi Offer
HoliOffer hOffer = new HoliOffer(mCar);
Console.WriteLine(“{0} {1} Holi price: {2} after discount of {3} percent”, mCar.GetBrand(), mCar.GetModel(), hOffer.NewPrice(), hOffer.PercentDiscount);
خروجی:
آموزشگاه برنامه نویسی تحلیل داده
HyundaiCar mCar2 = new HyundaiCar();
Console.WriteLine(“{0} {1} Regular price: {2}”, mCar2.GetBrand(), mCar2.GetModel(), mCar2.GetPrice());
//Diwali Offer
DiwaliOffer dOffer2 = new DiwaliOffer(mCar2);
Console.WriteLine(“{0} {1} Diwali price: {2} after discount of {3} percent”, mCar2.GetBrand(), mCar2.GetModel(), dOffer2.NewPrice(), dOffer2.PercentDiscount);
//Holi Offer
HoliOffer hOffer2 = new HoliOffer(mCar2);
Console.WriteLine(“{0} {1} Holi price: {2} after discount of {3} percent”, mCar2.GetBrand(), mCar2.GetModel(), hOffer2.NewPrice(), hOffer2.PercentDiscount);
خروجی:
آموزشگاه برنامه نویسی تحلیل داده
به طور خلاصه، از الگوی طراحی زمانی استفاده می شود که می خواهیم یک رفتار یا قابلیت پویا را، بدون تحت تاثیر قرار دادن کلاس های base، به شی از قبل موجود اضافه کنیم.