Behavioral DESIGN PATTERNS
یکی از زیرشاخه های الگوهای طراحی، Behavioral Design Patterns است. تمرکز و وظیفه اصلی این دیزاین پترن ها تعامل اشیاء و جداسازی وظایف آن ها از یکدیگر است.
Strategy Design Pattern
دیزاین پترن Strategy یکی از زیرشاخه های الگوهای طراحی از نوع Behavioral است.
الگوی طراحی استراتژی خانواده ای از الگوریتم ها را تعریف می کند ، هر یک را در بر می گیرد و آنها را قابل تعویض می کند. این الگو به الگوریتم اجازه می دهد تا مستقل از مشتریانی که از آن استفاده می کنند متفاوت باشد.
سختش نکنیم! هروقت برای انجام یک کار چندین روش داشتیم برای پیاده سازی از این دیزاین پترن استفاده میکنیم. به طور مثال برای ارسال پیامک میتوانیم از طریق چندین شرکت تامین کننده اس ام اس ارسال کنیم. یا مثلا برای درگاه پرداخت چندین درگاه ممکن است داشته باشیم.
میزان استفاده : زیاد
پیاده سازی دیزاین پترن Strategy
فرض کنید ما سرویس دهنده دستگاه پوز هستیم. برای دریافت یک دستگاه پوز نیاز هست تا دستگاه پوز ما به یک شرکت PSP یا Payment Service Provider (فراهم کننده سرویس پرداخت) متصل باشد. به طور مثال دو شرکت ایرانکیش و پارسیان را به عنوان شرکت PSP داریم. برای همین یک enum به شکل زیر مینویسیم.
enum PSP { IranKish, Parsian, }
ما برای هر PSP سه کار اصلی انجام میدهیم. عملیات اضافه کردن یک دستگاه پوز. ویرایش اطلاعات یک دستگاه پوز و پیگیری وضعیت نصب دستگاه پوز.
interface IPSP { bool AddAcceptor(POS pos); bool EditAcceptor(POS pos); bool Inquery(int trackId); }
همینطور که در کد بالا مشاهده میکنید ما یک مدل به نام POS هم داریم.
class POS { public int TrackId { get; set; } public string MerchantName { get; set; } public string CustomerName { get; set; } public PSP PSP { get; set; } public override string ToString() { return $"{MerchantName} [{CustomerName}] ({TrackId}) -> {PSP.ToString()}"; } }
حالا ما باید به ازای هر شرکت فراهم کننده یک کلاس داشته باشیم که از کلاس IPSP ارث برده باشد.
class ParsianStrategy : IPSP { public bool AddAcceptor(POS pos) { Console.WriteLine("Add : " + pos.ToString()); return true; } public bool EditAcceptor(POS pos) { Console.WriteLine("Edit : " + pos.ToString()); return true; } public bool Inquery(int trackId) { Console.WriteLine("Inquery Parsian : " + trackId); return true; } }
class IranKishStrategy : IPSP { public bool AddAcceptor(POS pos) { Console.WriteLine("Add : " + pos.ToString()); return true; } public bool EditAcceptor(POS pos) { Console.WriteLine("Edit : " + pos.ToString()); return true; } public bool Inquery(int trackId) { Console.WriteLine("Inquery IranKish : " + trackId); return true; } }
در مثال واقعی ما در هر کدام از ۳ متد اصلی باید API مربوطه که از شرکت دریافت کردیم را صدا بزنیم.
حالا ما یک کلاس Context هم ایجاد میکنیم که از طریق ورودی constructor یکی از این کلاس های مربوط به PSP را ارسال میکنیم و این ۳ متد را با توجه به شرکت مربوطه صدا میزند.
class PSPContext : IPSP { private IPSP psp; public PSPContext(IPSP psp) { this.psp = psp; } public bool AddAcceptor(POS pos) { return psp.AddAcceptor(pos); } public bool EditAcceptor(POS pos) { return psp.EditAcceptor(pos); } public bool Inquery(int trackId) { return psp.Inquery(trackId); } }
حالا به کلاسی احتیاج داریم که بر اساس شرکت تامین کننده تصمیم بگیرد که از کدام کلاس استفاده کند برای ادامه کار. در اینجا تصمیم گرفته میشود که API های کدام شرکت صدا زده شود.
اگر به جای مثال PSP و POS مثلا میخواستیم از شرکت ارسال کننده SMS استفاده کنیم یا درگاه پرداخت، همین روال را باید طی کنیم.
به سراغ سرویس دهنده PSP برویم.
class PSPService : IPSP { private PSPContext context; private PSP psp; public PSPService(PSP psp) { this.psp = psp; } public bool AddAcceptor(POS pos) { switch (psp) { case Enums.PSP.IranKish: context = new PSPContext(new IranKishStrategy()); break; case Enums.PSP.Parsian: context = new PSPContext(new ParsianStrategy()); break; default: context = null; break; } if (context == null) return false; return context.AddAcceptor(pos); } public bool EditAcceptor(POS pos) { switch (psp) { case Enums.PSP.IranKish: context = new PSPContext(new IranKishStrategy()); break; case Enums.PSP.Parsian: context = new PSPContext(new ParsianStrategy()); break; default: context = null; break; } if (context == null) return false; return context.EditAcceptor(pos); } public bool Inquery(int trackId) { switch (psp) { case Enums.PSP.IranKish: context = new PSPContext(new IranKishStrategy()); break; case Enums.PSP.Parsian: context = new PSPContext(new ParsianStrategy()); break; default: context = null; break; } if (context == null) return false; return context.Inquery(trackId); } }
با توجه به اینکه کدام شرکت PSP را از طریق enum انتخاب کردیم در اینجا تصمیم گرفته میشود که به کدام API وصل شویم.
حالا نوبت به صدا زدن متد main میشود.
static void Main(string[] args) { try { var pos = new POS() { CustomerName = "Hossein Badrnezhad", MerchantName = "Online Shop", PSP = PSP.IranKish, TrackId = 1024 }; PSPService service = new PSPService(pos.PSP); service.AddAcceptor(pos); service.EditAcceptor(pos); service.Inquery(pos.TrackId); } catch (Exception ex) { ShowError(ex.Message); } Console.ReadLine(); }
برای آموزش رایگان در مورد انواع دیزاین پترن ها و معماری های نرم افزار می توانید به این آموزش مراجعه نمایید:
معماری نرم افزار مهم ترین پترن های معماری نرم افزار
دیزاین پترن یا الگوی طراحی چیست؟
دیزاین پترن در حقیقت راه حل مسائل طراحی نرم افزار هستند که بارها و بارها در دنیای توسعه نرم افزار تکرار میشوند. الگوهایی از طراحی قابل استفاده مجدد (reusable) و تعامل اشیاء.
نظرات