کانال بله, جهت پشتیبانی و اطلاع رسانی کانال بله, جهت پشتیبانی و اطلاع رسانی
عضویت

نحوه تزریق وابستگی

تزریق وابستگی

در فصل قبل DIP برای درست کردن کلاس های با همراهی آزادانه ، انتزاع را ایجاد و از آن استفاده کردیم. در این بخش می خواهیم برای انتقال کامل ایجاد کردن شیء وابسته به خارج از کلاس، تزریق وابستگی و الگوی استراتژی را پیاده سازی کنیم. این سومین قدم به سمت ایجاد کلاس های با همراهی کاملا آزادانه است.


آموزش Inversion Of Control

تزریق وابستگی (DI) یک الگوی طراحی است که در پیاده سازی IoC کاربرد دارد. به کمک DI می توان اشیاء وابسته را خارج از یک کلاس ایجاد کرد و این اشیاء را از راه های متفاوتی در اختیار یک کلاس گذاشت. با استفاده از DI می توانیم ایجاد و binding اشیاء وابسته را به خارج از کلاس وابسته به آن ببریم.
تزریق وابستگی شامل 3 نوع کلاس می شود :

  1. کلاس کلاینت : کلاس کلاینت ( کلاس وابسته) کلاسی اسا که به کلاس سرویس وابسته است
  2. کلاس سرویس: کلاس سرویس (وابستگی) کلاسی است که خدمات را در اختیار کلاس کلاینت قرار می دهد.
  3. کلاس تزریق کننده : کلاسی است که شیء کلاس سرویس را در کلاس کلاینت تزریق می کند.

در شکل زیر ارتباط بین این کلاس ها را می توانید مشاهده کنید:


آموزش Inversion Of Control

همانطور که می بینید کلاس تزریق کننده، شیئی از کلاس سرویس را ایجاد می کند و این شیء را در یک شیء کلاینت تزریق می کند. به این شیوه، الگوی DI مسئولیت ایجاد شیئی از کلاس سرویس را به خارج از کلاس کلاینت می برد.


انواع تزریق وابستگی

همانطور که در بالا آموختید، کلاس تزریق کننده سرویس ( وابستگی) را در کلاینت ( وابسته) تزریق می کند. این کلاس به طور گسترده وابستگی ها را به سه صورت تزریق می کند : از طریق constructor، مشخصه و یا متد .
تزریق constructor : طی این فرایند، تزریق کننده از طریق constructor کلاس کلاینت سرویس (وابستگی) را تامین می کند.
تزریق مشخصه : طی تزریق مشخصه ( معروف به تزریق قراردهنده (setter) ) ، تزریق کننده از طریق یکی از مشخصه ی عمومی کلاس کلاینت ، وابستگی را تامین می کند.
تزریق متد : در این نوع از تزریق، کلاس کلاینت رابطی را پیاده سازی می کند که در آن برای تامین وابستگی متد یا متدهایی را اعلان می کند. تزریق کننده از این رابط جهت تامین کردن وابستگی برای کلاس کلاینت استفاده می کند.
بیاید برای حفظ یکپارچگی و پیوستگی موضوع، از مثال فصل قبل استفاده کنیم. در بخش DIP ، مانند زیر برای دریافت شیئی از شیء CustomerDataAccess از کلاس Factory استفاده کردیم.

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

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

    public string GetCustomerName(int id) {
        return "Dummy Customer Name";        
    }
}

public class DataAccessFactory
{
    public static ICustomerDataAccess GetCustomerDataAccessObj() 
    {
        return new CustomerDataAccess();
    }
}

public class CustomerBusinessLogic
{
    ICustomerDataAccess _custDataAccess;

    public CustomerBusinessLogic()
    {
        _custDataAccess = DataAccessFactory.GetCustomerDataAccessObj();
    }

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

مشکلی که در مثال بالا وجود دارد این است که ما از DataAccessFactory در داخل کلاسCustomerBusinessLogic استفاده کرده ایم. پس فرض کنید که بنابر دلیلی پیاده سازی دیگری از ICustomerDataAccess وجود دارد و ما می خواهیم در CustomerBusinessLogic از این کلاس جدید استفاده کنیم. پس از آن باید سورس کد کلاس CustomerBusinessLogic را نیز تغییر دهیم. الگوی تزریق وابستگی با تزریق اشیاء وابسته از طریق constructor ، مشخصه و یا رابط این مشکل را حل می کند.
در شکل زیر پیاده سازی الگوی DI مربوط به مثال بالا نشان داده شده است.


آموزش Inversion Of Control

همانطور که می بینید، کلاس CustomerService به یک کلاس تزریق کننده تبدیل می شود به گونه ای که برای دستیابی به همراهی آزادانه از طریق constructor ، مشخصه و یا متد شیئی از کلاس سرویس (CustomerDataAccess) را بر روی کلاس کلاینت (CustomerBusinessLogic) تنظیم می کند. اجازه دهید هر یک از این گزینه ها را بیشتر بررسی کنیم.

تزریق constructor

همانطور که قبلا نیز اشاره کردیم، زمانی که از طریق constructor وابستگی ای را فراهم کنیم به این کار تزریق contructor می گوییم.
به مثال زیر توجه کنید. در این مثال DI را با استفاده از constructor پیاده سازی کرده ایم.
مثال : تزریق constructor

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 GetCustomerData(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 شامل constructor ای با پارامتر از نوع IcustomerDataAccess است. حالا کلاس فراخواننده باید شی از IcustomerDataAccess را تزریق کند.
مثال : تزریق وابستگی

public class CustomerService
{
    CustomerBusinessLogic _customerBL;

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

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

همانطور که در مثال بالا می بینید، کلاس CustomerService شیء CustomerDataAccess را ایجاد و آن را در کلاس CustomerBusinessLogic تزریق می کند. به این صورت، کلاس CustomerBusinessLogic دیگری نیازی ندارد که با استفاده از عبارت کلیدی new یا کلاس factory شیئی از CustomerDataAccess را ایجاد کند. کلاس فراخواننده (CustomerService) کلاس DataAccess مناسب را ایجاد و آن را بر روی کلاس CustomerBusinessLogic تنظیم می کند. به این شیوه همراهی آزادانه ی CustomerBusinessLogic و کلاس CustomerDataAccess بیش از پیش افزایش می یابد.

تزریق مشخصه

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

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 را ایجاد و آن را تنظیم می کند.


تزریق متد

طی تزریق متد، وابستگی ها از طریق متدها فراهم می شوند. این متد می تواند یک متد کلاسی یا رابطی باشد.
به مثال زیر توجه کنید. در این مثال نحوه ی تزریق متد با استفاده از متد رابطی نشان داده شده است:
مثال : تزریق رابط

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 را پیاده سازی می کند. بنابراین، کلاس تزریق کننده (CustomerService) برای تزریق کلاس وابسته (CustomerDataAccess) در کلاس کلاینت از این متد استفاده می کند.
به این شیوه می توانید برای ایجاد کلاس های با همراهی آزادانه از الگوی استراتژی و DI استفاده کنید.
تا به اینجای کار، ما برای دستیابی به کلاس های دارای همراهی آزادانه از چند اصل و الگو استفاده کرده ایم. در پروژه های حرفه ای کلاس های وابسته ی زیادی وجود دارند و پیاده سازی این الگو ها ممکن است زمانبر باشد. در این صورت نگهدارنده ی IoC ( معروف به نگهدارنده ی DI ) می تواند به کمک ما بیاید. در فصل بعد بیشتر به این موضوع خواهیم پرداخت.


برای مطالعه سرفصل اصول و الگوهای طراحی شی گرا - Object Oriented Design Principles & Patterns کلیک نمایید .

1397/07/17 2690 854
رمز عبور : tahlildadeh.com یا www.tahlildadeh.com
نظرات شما

نظرات خود را ثبت کنید...