اصل Dependency Inversion چیست؟
در سري پست هاي تعريف اصول SOLID با
آشنا شديم در اين پست پنجمین اصل يعني Dependency inversion رو برسي ميكنيم.
هدف Dependency inversion اینه که کلاس های سطح بالا نبایستی به صورت مستقیم وابسته به کلاس های سطح پایین باشن بلکه رابطه ی بین کلاس ها بایستی براساس Abstract ها یا Interface ها باشه. بعنوان مثال اگه کلاس سطح بالای سیستم رو business logic بدونیم و این سطح وابسته به جزئیات سطح پایین مثلا ذخیره در بانک اطلاعاتی باشه
- استفاده مجدد از کلاس های business logic مارو کم میکنه
- انجام تست روی کلاس های business logic ما سخت میشه
عکس زیر برگرفته از کتاب Dependency Injection in .NET هست که Dependency Injection (الگويي براي رعايت اين اصل) رو بخوبی توضیح داده
مدير يك هتل ارزان قيمت براي اينكه سشوار دزيده نشه اونو به پريز بسته و اين يعني وابستگي بين سشوار و پريز تغيير در هركدوم ;ديگري رو تحت تاثير قرار ميده.
و اما براي مثال عملي فرض كنيد کلاسی بنام GetMessageFromDatabase داریم که یک پیغام رو از دیتابیس لود میکنه و کلاسی بنام DisplayMessage داریم که اون پیغام رو نمایش میده.
class Program { static void Main(string[] args) { DisplayMessage dm = new DisplayMessage(); dm.ShowMessage(); } } public class DisplayMessage { GetMessageFromDatabase Gmd; public DisplayMessage() { Gmd = new GetMessageFromDatabase(); } public void ShowMessage() { Console.WriteLine(Gmd.GetMessage()); Console.ReadLine(); } } public class GetMessageFromDatabase { public string GetMessage() { return "Hi from database"; } }
فرض کنید چند وقت دیگه سیستم نیاز پیدا میکنه که پیغام علاوه بر دیتابیس از یک فایل XML هم خونده بشه.
public void ShowMessage() { if (source.ToUpper() == "DATABASE") { GetMessageFromDatabase Gmd = new GetMessageFromDatabase(); Console.WriteLine(Gmd.GetMessage()); Console.ReadLine(); } else if (source.ToUpper() == "XML") { GetMessageFromXML Gmx = new GetMessageFromXML(); Console.WriteLine(Gmx.GetMessage()); Console.ReadLine(); } }
چند وقت دیگه هم نیاز به خوندن از فایل متنی و…
چیزی که مشخصه وابسته بودن کلاس DisplayMessage به جایی که پیغام از اون میاد هست و این یعنی نقض اصل Dependency inversion.
و اما برای رفع این مشکل از اینترفیس استفاد میکنیم. کلاس های GetMessageFromDatabase و GetMessageFromXML و … هم این اینترفیس رو پیاده سازی میکنن.
public interface IGetData { string GetMessage(); }
کلاس DisplayMessage رو هم به شکل زیر تغییر میدیم
public class DisplayMessage { IGetData IGLocal; public DisplayMessage(IGetData IG) { IGLocal = IG; } public void ShowMessage() { Console.WriteLine(IGLocal.GetMessage()); } }
نحوه فراخوانی هم بشکل زیر میشه
static void Main(string[] args) { IGetData IG; string source = args[0].ToString(); if (source.ToUpper() == "DATABASE") { IG = new GetMessageFromDatabase(); } else if (source.ToUpper() == "XML") { IG = new GetMessageFromXML(); } else if (source.ToUpper() == "TEXT") { IG = new GetMessageFromTextFile(); } else { IG = new GetMessageFromDatabase();//default set to database } DisplayMessage dm = new DisplayMessage(IG); dm.ShowMessage(); }
مطلب خوبی بود. خصوصاً اینکه مثال قابل لمسی داشت.
پاسخحذفموفق باشید