وارونگی وابستگی (dependency inversion)
نوشته شده توسط غلامرضا محمدی-
تاریخ ایجاد در دوشنبه, 04 دی 1396
-
بازدید: 671
dependency inversion یا وارونگی وابستگی یک الگوی طراحی است که در آن سعی بر رفع مشکل ماژولهای مرتبط شده است. این الگو دارای دو اصل اساسی است:
- ماژول بالادستی نباید به ماژول پایین دستی وابستگی داشته باشد. هر دو مازول باید انتزاعی از یک اینترفیس مشترک باشند.
- انتزاع نباید به جزئیات پیاده سازی هر مازول وابسته باشد.
به صورت سنتی ماژولهای سطح بالاتر همیشه به ماژولهای سطح پایینتر وابستگی دارند. اگر تصور کنیم که یک برنامه کاربردی دارای لایه های presentation,application,business,data access باشند. لایه بالایی یعنی presentation به لایه پایین دست خود یعنی application وابستگی دارد و برای انجام کار باید ابتدا مازولهای این لایه راه اندازی شوند تا لایه presentation بتواند به فعالیت خود ادامه دهد (مطابق شکل زیر).
بعد از اعمال اصل وارونگی وابستگی روابط بالا بالعکس می شوند و دیگر لایه بالادستی درگیر مسائل مربوط به لایه های پایینتر خود نمی باشد. در این حالت هر لایه دارای یک interface می باشد که از آن ارث بری می نماید و لایه های پایینتر نیز ارتباط خود را با لایه های بالادستی از طریق همین interface و با انتزاع از آنها برقرار می کنند. شکل زیر بیانگر پیاده سازی این اصل و چگونگی برقراری وابستگی هایبین لایه هاست:
برای بیشتر روشن شدن موضوع به مثال زیر توجه نمایید:
ما قصد داریم که یک سیستم نمایش پیام سمت کلاینت را راه اندازی نماییم. ما باید قادر به ارسال پیامهای متنی به صورت email و sms باشیم. در زیر تعدادی از کلاسهای مربوط به این مورد آمده است:
public class Email
{
public string ToAddress { get; set; }
public string Subject { get; set; }
public string Content { get; set; }
public void SendEmail()
{
//Send email
}
}
public class SMS
{
public string PhoneNumber { get; set; }
public string Message { get; set; }
public void SendSMS()
{
//Send sms
}
}
public class Notification
{
private Email _email;
private SMS _sms;
public Notification()
{
_email = new Email();
_sms = new SMS();
}
public void Send()
{
_email.SendEmail();
_sms.SendSMS();
}
}
همانطور که در کدهای بالا دیده می شود، کلاس notification کلاس بالادستی است و به هر دو کلاس پایین دستی خود email و sms دارای وابستگی می باشد. به عبارت دیگر کلاس notification وابسته به این است که ابتدا دو کلاس emai و sms پیاده سازی شوند تا بتواند کار خود را آغاز نماید. به این حالت که دو کلاس دارای وابستگی زیادی به هم هستند hi-coupling گفته می شود. برای رفع این مشکل باید اصل وارونگی وابستگی در مورد کلاسهای بالا رعایت شده و پیاده سازی کلاسها طبق آن صورت گیرد.
برای اجرای اصل ابتدا یک اینترفیس با نام IMessage حاوی جزئیات مشترک دو کلاس sms و email می سازیم. قطعه کد زیر این اینترفیس را نشان می دهد:
public interface IMessage
{
void SendMessage();
}
در مرحله بعد دو کلاس sms و email باید از این اینترفیس ارث بری کرده و تابع SendMessage() را پیاده سازی نمایند:
public class Email : IMessage
{
public string ToAddress { get; set; }
public string Subject { get; set; }
public string Content { get; set; }
public void SendMessage()
{
//Send email
}
}
public class SMS : IMessage
{
public string PhoneNumber { get; set; }
public string Message { get; set; }
public void SendMessage()
{
//Send sms
}
}
در پایان ما کلاس notification را با انتزاع از imessage به صورت زیر پیاده سازی می نماییم:
public class Notification
{
private ICollection<IMessage> _messages;
public Notification(ICollection<IMessage> messages)
{
this._messages = messages;
}
public void Send()
{
foreach(var message in _messages)
{
message.SendMessage();
}
}
}
همانطور که در مثال بالا دیده شد اصل وارونگی وابستگی که خود یکی از زیرمجموعه های وارونگی کنترل است، الگویی را به ما می دهد تا با کمک آن بتوانیم وابستگی های یک کلاس را بیرون از آن و فارغ از نحوه تعریف و پیاده سازی آن تعریف نموده و از آن استفاده نماییم. اما مشکل اینجاست که هنوز این اصل نحوه تزریق این وابستگیها را در کنترلر و توابع اصلی برنامه به ما نمی دهد. بطور مثال در کد بالا کلاس بالادستی Notification را چگونه و با رعایت اصول Loosely Coupling در کنترلر استفاده نماییم. در حقیقت این اصل تنها یک محیط ایزوله برای کلیه کلاسها ایجاد می نماید و برای ادامه کار باید سراغ یکی دیگر از الگوهای وارونگی کنترل (Inversion Of Control) یعنی تزریق وابستگی برویم.