زمان تخمینی مطالعه: 10 دقیقه

مقدمه

در واقع Dependency Injection یک قرارداد طراحی است که وابستگی‌های کد را با استفاده از اصل وارونگی کنترل (inversion of control-IOC) حل می‌کند. این الگو ارتباط یکپارچه‌ای بین اجزای نرم افزاری سازگار ایجاد می‌کند. توجه به این نکته مهم است که چالش حیاتی در توسعه نرم افزار، مدیریت و درک تزریق وابستگی است. توسعه‌دهنده‌ای که از الگوی طراحی(Design Pattern) استفاده می‌کند، کد قابل خواندن، کارآمد و انعطاف‌پذیر تولید می‌کند.

مفهوم Dependency Injection چیست؟

تزریق وابستگی (Dependency Injection) یک روش برنامه نویسی است که ایجاد و استفاده از اجزا را از هم جدا می‌کند. الگوی طراحی(DP) در برنامه نویسی شی‌گرا ظاهر شده و به اصول SOLID (مخصوصاً S و D) پایبند است. ایده‌های مشابه در مورد سایر پارادایم‌های برنامه نویسی مانند برنامه نویسی امری یا اعلانی نیز اعمال می‌شود. Dependency Injection شامل دو کلمه کلیدی است که به ابهام‌زدایی از مفهوم آن کمک می‌کند:

وابستگی‌ها در فرم‌ها و اشکال مختلفی وجود دارند. آنها برای کارکرد یک جزء ضروری هستند اما بخشی از خود جزء نیستند. API ها، کتابخانه‌ها، پایگاه‌های داده و سایر مؤلفه‌ها همگی می‌توانند به عنوان وابستگی عمل کنند. تزریق وابستگی چالش مدیریت وابستگی را حل می‌کند. با جدا کردن مدیریت وابستگی از یک جزء، یک منبع خارجی وابستگی‌ها را ایجاد و مدیریت می‌کند.

جداسازی (decoupling) تعداد اتصالات بین اجزا و ماژول‌ها را کاهش می‌دهد. اتصالات کمتر منجر به تعمیر و نگهداری ساده و انعطاف پذیری می‌شود. در نتیجه، کد قابل استفاده مجدد می‌شود زیرا مؤلفه‌ها مستقل هستند و در زمینه‌های مختلف قابل استفاده هستند. تیم‌های توسعه دیگر نیازی به هماهنگی مداوم ندارند و می‌توانند ماژول‌ها را به صورت موازی توسعه دهند.

چرا از Dependency Injection استفاده کنیم؟

دلایل بسیاری برای استفاده از تزریق وابستگی(DI) وجود دارد. برخی از مهم‌ترین مزایای آن عبارتند از:

انواع Dependency Injection کدامند؟

توسعه دهندگان از تکنیک‌های مختلفی برای اجرای Dependency Injection استفاده می‌کنند. در انتخاب آن رویکردی را انتخاب کنید که به بهترین وجه با الزامات، زبان برنامه نویسی و موارد استفاده مطابقت دارد. در ادامه مروری مختصر و نمونه‌ای از انواع Dependency Injection آورده شده است:

Dependency Injection چگونه کار می‌کند؟

فرآیند تزریق وابستگی از چهار جزء اصلی (نقش) استفاده می‌کند:

  1. خدمات(Service): مؤلفه‌ای که عملکرد یا سرویسی را ارائه می‌دهد. سایر اجزا به خدمات ارائه شده بستگی دارد.
  2. مشتری(Client): جزء یا کلاسی که برای انجام وظایف به سرویس بستگی دارد. مشتری سرویس را ایجاد یا مدیریت نمی‌کند. برای ارائه خدمات به فرآیند Dependency Injection متکی است.
  3. تزریق کننده(Injector): نمونه‌های سرویس را ایجاد و مدیریت می‌کند و آنها را به مشتریان تزریق می‌کند. تزریق کننده تمام وابستگی‌ها را برطرف کرده و قطعات را در صورت لزوم به هم متصل می‌کند.
  4. رابط(Interface): رابط (یا قرارداد) متدها یا ویژگی‌هایی که یک سرویس پیاده سازی می‌کند را تعریف می‌کند. مفهوم انتزاع توافقی است بین خدمات و مشتری، که تضمین می‌کند این سرویس به تمام قوانین و انتظارات پاسخ می‌دهد.

فرآیند Dependency Injection مراحل زیر را طی می‌کند:

مزایا و معایب Dependency Injection

در هنگام اجرای تزریق وابستگی هم مزایا و هم معایبی وجود دارند. اگرچه این رویکرد قابلیت نگهداری کد را بهبود می‌بخشد اما منحنی یادگیری دارای شیب زیادی است و پیچیدگی کد با استفاده از DI بالا خواند رفت. در ادامه مروری کوتاه بر مزایا و معایب اصلی Dependency Injection خواهیم داشت:

مزایا:

– معایب:

مثال عملی Dependency Injection

– Constructor Injection: همانطور که قبلا ذکر شد، زمانی که وابستگی را از طریق سازنده ارائه می‌کنیم، به آن Constructor Injection می‌گویند.مثال زیر را در نظر بگیرید که در آن DI را با استفاده از سازنده پیاده سازی کرده‌ایم:

public class CustomerBusinessLogic
{
    ICustomerDataAccess _dataAccess;

    public CustomerBusinessLogic(ICustomerDataAccess custDataAccess)
    {
        _dataAccess = custDataAccess;
    }

    public CustomerBusinessLogic()
    {
        _dataAccess = new CustomerDataAccess();
    }

    public string ProcessCustomerData(int id)
    {
        return _dataAccess.GetCustomerName(id);
    }
}

public interface ICustomerDataAccess
{
    string GetCustomerName(int id);
}

public class CustomerDataAccess: ICustomerDataAccess
{
    public CustomerDataAccess()
    {
    }

    public string GetCustomerName(int id) 
    {
        //get the customer name from the db in real application        
        return "Dummy Customer Name"; 
    }
}

در مثال بالا، CustomerBusinessLogic شامل سازنده با یک پارامتر از نوع ICustomerDataAccess است. اکنون، کلاس فراخوان باید یک شی از ICustomerDataAccess را تزریق کند.

public class CustomerService
{
    CustomerBusinessLogic _customerBL;

    public CustomerService()
    {
        _customerBL = new CustomerBusinessLogic(new CustomerDataAccess());
    }

    public string GetCustomerName(int id) {
        return _customerBL.ProcessCustomerData(id);
    }
}

همانطور که در مثال بالا می‌بینید، کلاس CustomerService شی CustomerDataAccess را ایجاد کرده و به کلاس CustomerBusinessLogic تزریق می‌کند. بنابراین، کلاس CustomerBusinessLogic نیازی به ایجاد یک شی از CustomerDataAccess با استفاده از کلمه کلیدی جدید یا با استفاده از کلاس کارخانه(Factory) ندارد. کلاس فراخوان (CustomerService) کلاس DataAccess مناسب را برای کلاس CustomerBusinessLogic ایجاد و تنظیم می‌کند. به این ترتیب، کلاس‌های CustomerBusinessLogic و CustomerDataAccess به کلاس‌های «بیش‌تر» تبدیل می‌شوند که با هم جفت شده‌اند.

– Setter Injection: در این نوع تزریق، وابستگی از طریق ویژگی عمومی تامین می‌شود. مثال زیر را در نظر بگیرید:

public class CustomerBusinessLogic
{
    public CustomerBusinessLogic()
    {
    }

    public string GetCustomerName(int id)
    {
        return DataAccess.GetCustomerName(id);
    }

    public ICustomerDataAccess DataAccess { get; set; }
}

public class CustomerService
{
    CustomerBusinessLogic _customerBL;

    public CustomerService()
    {
        _customerBL = new CustomerBusinessLogic();
        _customerBL.DataAccess = new CustomerDataAccess();
    }

    public string GetCustomerName(int id) {
        return _customerBL.GetCustomerName(id);
    }
}

همانطور که در بالا می‌بینید، کلاس CustomerBusinessLogic شامل ویژگی عمومی به نام DataAccess است که در آن می‌توانید نمونه‌ای از کلاسی را تنظیم کنید که ICustomerDataAccess را پیاده سازی می‌کند. بنابراین، کلاس CustomerService با استفاده از این ویژگی عمومی، کلاس CustomerDataAccess را ایجاد و تنظیم می‌کند.

– Method Injection: در روش تزریق متد، وابستگی‌ها از طریق متدها فراهم می‌شود. این متد می‌تواند یک متد کلاس یا یک متد رابط باشد. مثال زیر تزریق متد را با استفاده از روش مبتنی بر رابط نشان می‌دهد:

interface IDataAccessDependency
{
    void SetDependency(ICustomerDataAccess customerDataAccess);
}

public class CustomerBusinessLogic : IDataAccessDependency
{
    ICustomerDataAccess _dataAccess;

    public CustomerBusinessLogic()
    {
    }

    public string GetCustomerName(int id)
    {
        return _dataAccess.GetCustomerName(id);
    }
        
    public void SetDependency(ICustomerDataAccess customerDataAccess)
    {
        _dataAccess = customerDataAccess;
    }
}

public class CustomerService
{
    CustomerBusinessLogic _customerBL;

    public CustomerService()
    {
        _customerBL = new CustomerBusinessLogic();
        ((IDataAccessDependency)_customerBL).SetDependency(new CustomerDataAccess());
    }

    public string GetCustomerName(int id) {
        return _customerBL.GetCustomerName(id);
    }
}

در مثال بالا، کلاس CustomerBusinessLogic رابط IDataAccessDependency را پیاده سازی می‌کند که شامل متد ()SetDependency است. بنابراین، کلاس injector CustomerService اکنون از این روش برای تزریق کلاس وابسته (CustomerDataAccess) به کلاس مشتری استفاده می‌کند.

نتیجه گیری

پس از خواندن این مقاله راهنما در مورد مفهوم Dependency Injection ، اکنون دیگر می‌دانید تزریق وابستگی چیست، انواع آن کدام است و چگونه می‌تواند قابلیت نگهداری کد را بهبود بخشد. همچنین با دیدن نمونه کدهای ارائه شده دیدی بهتر نسبت آن پیدا کردید. امیدواریم با این مطالب بتوایند روز به روز بر دانش برنامه نویسی خود بیفزاید و ما هم در تیم الکتروهایو در تلاش برای فراهم کردن مقالات مفید برای مخاطبان عزیز هستیم.

 

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *