قبل از شروع، من از شما درخواست می کنم که از مقالات قبلی در مجموعه الگوهای طراحی دیدن کنید :
- الگوهای طراحی ساده شده: قسمت 1
- الگوهای طراحی ساده شده - قسمت 2 (Singleton)
- الگوهای طراحی ساده شده - قسمت 3 (کارخانه ساده)
- الگوهای طراحی ساده شده - قسمت 4 (کارخانه انتزاعی)
- الگوهای طراحی ساده شده - قسمت 5 ( روش کارخانه)
- الگوهای طراحی ساده شده - قسمت 6 (نمونه اولیه)
- الگوهای طراحی ساده شده - قسمت 7 (سازنده)
- الگوهای طراحی ساده شده - قسمت 8 (نما)
- الگوهای طراحی ساده شده - قسمت 9 (آداپتور)
من اینجا هستم تا بحث پیرامون الگوهای طراحی را ادامه دهم. امروز یکی از الگوهای طراحی سازه به نام دکوراتور را مرور می کنیم. قبل از صحبت در مورد اجرای آن، اجازه دهید با تعریف آن شروع کنیم. مطابق با بچه های GOF، الگوی دکوراتور به صورت زیر تعریف می شود:
خوب! بیایید منظور آنها را بفهمیم.
منظورشان این است که اگر بخواهیم به صورت پویا مسئولیت را به هر شی اضافه کنیم، میتوانیم به جای طبقهبندی فرعی، سراغ الگوی Decorator برویم. طبقهبندی فرعی روش معمولی برای رسیدگی به هر رفتار اضافهای بوده است، اما در هنگام برخورد با زیر کلاسهای متعدد، حفظ آن کثیف و دشوار میشود. از سوی دیگر، الگوی دکوراتور راه آسانی را برای مدیریت نه تنها چندین زیر کلاس، بلکه ترکیب آنها نیز فراهم می کند.
الگوی دکوراتور نیز اصل "باز-بسته" را اعمال می کند که یکی از اصول طراحی جامد است. در مقالههای آینده در مورد اصل SOLID صحبت خواهیم کرد، اما به طور خلاصه، اصل Open-Closed پیشنهاد میکند که کلاسها باید برای گسترش باز و بسته برای اصلاح باشند.
نحوه عملکرد الگوی دکوراتور
الگوی دکوراتور دارای چهار عنصر کلیدی است که در زیر آمده است.
- Component: این یک رابط از شی است که می خواهیم رفتار پویا را در آن اضافه کنیم.
- ConcreateComponent: این یک پیاده سازی دقیق از Component است.
- Decorator : معمولاً کلاس انتزاعی است که رفتار پویا را تعریف می کند. همچنین Component را پیاده سازی می کند
- ConcreateDecorator : اجرای بتن Decorator. هر قابلیت پویا ConcreateDecorator خود را پیاده سازی می کند.
این را با مثال ساده متوجه خواهیم شد.
بیایید با ایجاد کامپوننت شروع کنیم و نمونه خودرو مشابهی را که در مقالههای قبلی گرفتیم، در نظر بگیریم.
- ///<summary>
- /// The component
- ///</summary>
- public interface IVehicle
- {
- string GetBrand();
- string GetModel();
- int GetPrice();
- }
حال بیایید کلاس های ConcreateComponent را تعریف کنیم. در اینجا دو کلاس از این قبیل را تعریف می کنیم.
- ///<summary>
- /// The concrete component
- ///</summary>
- public class MarutiCar: IVehicle
- {
- public string GetBrand()
- {
- return "Maruti";
- }
- public string GetModel()
- {
- return "Swift VXI";
- }
- public int GetPrice()
- {
- return 610000;
- }
- }
- ///<summary>
- /// The concrete component
- ///</summary>
- public class HyundaiCar: IVehicle
- {
- public string GetBrand()
- {
- return "Hyundai";
- }
- public string GetModel()
- {
- return "Grand i10 Magna";
- }
- public int GetPrice()
- {
- return 540000;
- }
- }
اکنون زمان تعریف کلاس Decorator فرا رسیده است. رابط Component را پیاده سازی می کند و به عنوان یک کلاس پایه برای رفتارهای پویا عمل می کند.
- ///<summary>
- /// The Decorator abstract class
- ///</summary>
- 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();
- }
- }
تا اینجا خوبه!! اکنون کلاس های دکوراتور بتن را طوری طراحی کنید که رفتار پویا را مانند زیر انجام دهد.
- 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 اضافه کرده ایم. ممکن است چندین کلاس از این قبیل برای رسیدگی به مناسبت های مختلف وجود داشته باشد.
راهاندازی اکنون آماده است. بیایید از آنها در مشتری استفاده کنیم و عمل را ببینیم.
- 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);
خروجی:
همچنین می توانید به کد موجود در نمونه پیوست مراجعه کنید.
به طور خلاصه، الگوی دکوراتور را می توان زمانی استفاده کرد که بخواهیم رفتار یا عملکرد پویا را به اشیاء موجود اضافه کنیم و همچنین بدون تأثیر بر کلاس های پایه.
امیدوارم که مقاله را دوست داشته باشید. منتظر نظرات/پیشنهادات شما باشید.
مقالات بیشتر در مورد الگوهای طراحی را بخوانید :