رتبه موضوع:
  • 0 رای - 0 میانگین
  • 1
  • 2
  • 3
  • 4
  • 5
تزریق وابستگی (dependency injection) به زبان ساده
#1
به صورت خلاصه ترزیق وابستگی و یا dependency injection ، الگویی است جهت تزریق وابستگی‌های خارجی یک کلاس به آن، بجای استفاده مستقیم از آن‌ها در درون کلاس.
برای مثال شخصی را در نظر بگیرید که قصد خرید دارد. این شخص می‌تواند به سادگی با کمک یک خودرو خود را به اولین محل خرید مورد نظر برساند. حال تصور کنید که 7 نفر عضو یک گروه، با هم قصد خرید دارند. خوشبختانه چون تمام خودروها یک اینترفیس مشخصی داشته و کار کردن با آن‌ها تقریبا شبیه به یکدیگر است، حتی اگر از یک ون هم جهت رسیدن به مقصد استفاده شود، امکان استفاده و راندن آن همانند سایر خودروها می‌باشد و این دقیقا همان مطلبی است که هدف غایی الگوی تزریق وابستگی‌ها است. بجای این‌که همیشه محدود به یک خودرو برای استفاده باشیم، بنابر شرایط، خودروی متناسبی را نیز می‌توان مورد استفاده قرار داد.
در دنیای نرم افزار، وابستگی کلاس Driver ، کلاس Car است. اگر موارد ذکر شده را بدون استفاده از تزریق وابستگی‌ها پیاده سازی کنیم به کلاس‌های زیر خواهیم رسید:
کد:
    //Person.cs
namespace DependencyInjectionForDummies
{
   class Person
   {
       public string Name { get; set; }
   }
}
کد:
//Car.cs
using System;
using System.Collections.Generic;

namespace DependencyInjectionForDummies
{
   class Car
   {
       List<Person> _passengers = new List<Person>();

       public void AddPassenger(Person p)
       {
           _passengers.Add(p);
           Console.WriteLine("{0} added!", p.Name);
       }

       public void Drive()
       {
           foreach (var passenger in _passengers)
               Console.WriteLine("Driving {0} ...!", passenger.Name);
       }
   }
}
کد:
//Driver.cs
using System.Collections.Generic;

namespace DependencyInjectionForDummies
{
   class Driver
   {
       private Car _myCar = new Car();

       public void DriveToMarket(IList<Person> passengers)
       {
           foreach (var passenger in passengers)
               _myCar.AddPassenger(passenger);

           _myCar.Drive();
       }
   }
}
کد:
    //Program.cs
using System.Collections.Generic;
using System;

namespace DependencyInjectionForDummies
{
   class Program
   {
       static void Main(string[] args)
       {
           new Driver().DriveToMarket(
               new List<Person>
               {
                   new Person{ Name="Ali" },
                   new Person{ Name="Vahid" }
               });

           Console.WriteLine("Press a key ...");
           Console.ReadKey();
       }
   }
}
توضیحات:
کلاس شخص (Person) جهت تعریف مسافرین، اضافه شده؛ سپس کلاس خودرو (Car) که اشخاص را می‌توان به آن اضافه کرده و سپس به مقصد رساند، تعریف گردیده است. همچنین کلاس راننده (Driver) که بر اساس لیست مسافرین، آن‌ها را به خودروی خاص ذکر شده هدایت کرده و سپس آن‌ها را با کمک کلاس خودرو به مقصد می‌رساند؛ نیز تعریف شده است. در پایان هم یک کلاینت ساده جهت استفاده از این کلاس‌ها ذکر شده است.
همانطور که ملاحظه می‌کنید کلاس راننده به کلاس خودرو گره خورده است و این راننده همیشه تنها از یک نوع خودروی مشخص می‌تواند استفاده کند و اگر روزی قرار شد از یک ون کمک گرفته شود، این کلاس باید بازنویسی شود.

خوب! اکنون اگر این کلاس‌ها را بر اساس الگوی تزریق وابستگی‌ها (روش تزریق در سازنده که در قسمت قبل بحث شد) بازنویسی کنیم به کلاس‌های زیر خواهیم رسید:
کد:
    
//ICar.cs
using System;

namespace DependencyInjectionForDummies
{
   interface ICar
   {
       void AddPassenger(Person p);
       void Drive();
   }
}
کد:
//Car.cs
using System;
using System.Collections.Generic;

namespace DependencyInjectionForDummies
{
   class Car : ICar
   {
       //همانند قسمت قبل
   }
}
کد:
//Van.cs
using System;
using System.Collections.Generic;

namespace DependencyInjectionForDummies
{
   class Van : ICar
   {
       List<Person> _passengers = new List<Person>();

       public void AddPassenger(Person p)
       {
           _passengers.Add(p);
           Console.WriteLine("{0} added!", p.Name);
       }

       public void Drive()
       {
           foreach (var passenger in _passengers)
               Console.WriteLine("Driving {0} ...!", passenger.Name);
       }
   }
}
کد:
    //Driver.cs
using System.Collections.Generic;

namespace DependencyInjectionForDummies
{
   class Driver
   {
       private ICar _myCar;

       public Driver(ICar myCar)
       {
           _myCar = myCar;
       }

       public void DriveToMarket(IList<Person> passengers)
       {
           foreach (var passenger in passengers)
               _myCar.AddPassenger(passenger);

           _myCar.Drive();
       }
   }
}

کد:
    //Program.cs
using System.Collections.Generic;
using System;

namespace DependencyInjectionForDummies
{
   class Program
   {
       static void Main(string[] args)
       {
           Driver driver = new Driver(new Van());
           driver.DriveToMarket(
               new List<Person>
               {
                   new Person{ Name="Ali" },
                   new Person{ Name="Vahid" }
               });

           Console.WriteLine("Press a key ...");
           Console.ReadKey();
       }
   }
}
توضیحات:
در اینجا یک اینترفیس جدید به نام ICar اضافه شده است و بر اساس آن می‌توان خودروهای مختلفی را با نحوه‌ی بکارگیری یکسان اما با جزئیات پیاده سازی متفاوت تعریف کرد. برای مثال در ادامه، یک کلاس ون با پیاده سازی این اینترفیس تشکیل شده است. سپس کلاس راننده‌ی ما بر اساس ترزیق این اینترفیس در سازنده‌ی آن بازنویسی شده است. اکنون این کلاس دیگر نمی‌داند که دقیقا چه خودرویی را باید مورد استفاده قرار دهد و از وابستگی مستقیم به نوعی خاص از آن‌ها رها شده است؛ اما می‌داند که تمام خودروها، اینترفیس مشخص و یکسانی دارند. به تمام آن‌ها می‌توان مسافرانی را افزود و سپس به مقصد رساند. در پایان نیز یک راننده جدید بر اساس خودروی ون تعریف شده، سپس یک سری مسافر نیز تعریف گردیده و نهایتا متد DriveToMarket فراخوانی شده است.
به این صورت به یک سری کلاس اصطلاحا loosely coupled رسیده‌ایم. دیگر راننده‌ی ما وابسته‌ی به یک خودروی خاص نیست و هر زمانی که لازم بود می‌توان خودروی مورد استفاده‌ی او را تغییر داد بدون اینکه کلاس راننده را بازنویسی کنیم.
یکی دیگر از مزایای تزریق وابستگی‌ها ساده سازی unit testing کلاس‌های برنامه توسط mocking frameworks است. به این صورت توسط این نوع فریم‌ورک‌ها می‌توان رفتار یک خودرو را تقلید کرد بجای اینکه واقعا با تمام ریز جرئیات آن‌ها بخواهیم سروکار داشته باشیم (وابستگی‌ها را به صورت مستقل می‌توان آزمایش کرد).

منبع
[عکس: <a href=www.Mojsazan.com.gif]" class="mycode_img" />
پاسخ
سپاس شده توسط مهدی ابراهیمی ، tara_sh500
#2
همیشه وقتی سورس نرم‌افزارهای Open Source را بررسی می‌کردم به یک چیز بی‌معنی برمی‌خوردم: استفاده بی‌مورد از interface. مثلاً کلاسی را پیدا می‌کردم که پیاده‌سازی یک اینترفیس خاص بود در حالی که خود آن اینترفیس هم فقط در همان یک جا مورد استفاده قرار گرفته بود. تا جایی که من می‌دانستم استفاده از interface وقتی خوب است که بخواهیم چندین و چند کلاس داشته باشیم که بخواهیم آن یک interface خاص را پیاده‌سازی کرده باشند. چند وقت پیش بالاخره به صرافت افتادم و در StackOverflow پرسیدم که چرا این روزها استفاده از interface این قدر باب شده است.

جواب خیلی واضح و قابل قبول بود. چون با استفاده از interfaceها می‌توان مفاهیمی مثل Dependency Injection و Decoupling را در نرم‌افزار پیاده‌سازی کرد. استفاده از این مفاهیم یعنی کلاس‌ها و دیگر بخش‌های برنامه را طوری بنویسیم که در حد ممکن از دیگر بخش‌ها بی‌خبر بوده و در نتیجه به آن وابستگی نداشته باشند. برنامه‌هایی که به این روش نوشته می‌شوند مدیریت و نگهداری راحت‌تری دارند و خواناتر هستند. علاوه بر این‌ها تکنیک‌های جدیدی که در TDD و Mocking استفاده می‌شوند در برنامه‌هایی که به روش Dependency Injection نوشته شده‌اند خیلی کاراتر و راحت‌تر عمل می‌کنند.
[عکس: <a href=www.Mojsazan.com.gif]" class="mycode_img" />
پاسخ
سپاس شده توسط
#3
بک کد ضمیمه میکنم برای دوستان آشنایی بیشتر

پسورد فایل ضمیمه "www.Mojsazan.com"


فایل‌های پیوست
.rar   DesignPatterns0509.rar (اندازه 18.86 KB / تعداد دانلود: 30)
[عکس: <a href=www.Mojsazan.com.gif]" class="mycode_img" />
پاسخ
سپاس شده توسط
#4
Mark Seemann کتاب Dependency Injection in .NET (تنها کتابی تخصصی ای که توانستم در مورد DI در دات نت پیدا کنم) را اینطور شروع می کند:
نقل قول:
Dependency Injection یکی از اشتباه برانگیز ترین (کم فهمیده شده ترین!) مفاهیم برنامه نویسی شیئ گرا ست. حوزه سردرگمی گسترده است و واژه شناسی، هدف، و مکانیک را در بر می گیرد. باید آن را Dependency Injection بنامیم، یا Inversion of Control، یا حتی Third-Party Connect؟ هدف DI تنها پشتیبانی از unit testing است یا هدف گسترده تری را دنبال می کند؟ آیا Dependency Injection همان Service Location است (این-همانی نه شباهت)؟ آیا وجود یک DI Container الزامی است؟
بعد، پیش از آن که وارد مبحث اصلی شود، توصیه می کند پیش از شروع کتاب، دانسته های پیشین را فراموش کنیم (you must unlearn before you can learn). مخصوصا یک لیست چهار تایی تهیه دیده است که از آن ها نه به عنوان اشتباه، بلکه به عنوان «افسانه» یاد می کند:
  • DI تنها مربوط به late binding است.
  • DI تنها مربوط به unit testing است.
  • DI به نوعی همان Abstract Factory است، اما در مقیاسی بزرگتر.
  • DI الزاما به یک DI Container نیاز دارد.
[عکس: <a href=www.Mojsazan.com.gif]" class="mycode_img" />
پاسخ
سپاس شده توسط tara_sh500
#5
هدف Dependency inversion اینه که کلاس های سطح بالا نبایستی به صورت مستقیم وابسته به کلاس های سطح پایین باشن بلکه رابطه ی بین کلاس ها بایستی براساس Abstract ها یا Interface ها باشه. بعنوان مثال اگه کلاس سطح بالای سیستم رو business logic بدونیم و این سطح وابسته به جزئیات سطح پایین مثلا ذخیره در بانک اطلاعاتی باشه

   استفاده مجدد از کلاس های business logic مارو کم میکنه
   انجام تست روی کلاس های business logic ما سخت میشه

عکس زیر برگرفته از کتاب Dependency Injection in .NET هست که Dependency Injection (الگويي براي رعايت اين اصل) رو بخوبی توضیح داده
[عکس: tightly%20coupled.jpg]

مدير يك هتل ارزان قيمت براي اينكه سشوار دزيده نشه اونو به پريز بسته و اين يعني وابستگي بين سشوار و پريز تغيير در هركدوم ;ديگري رو تحت تاثير قرار ميده.
و اما براي مثال عملي فرض كنيد کلاسی بنام GetMessageFromDatabase داریم که یک پیغام رو از دیتابیس لود میکنه و کلاسی بنام DisplayMessage داریم که اون پیغام رو نمایش میده.
کد:
01    class Program
02     {
03         static void Main(string[] args)
04         {
05             DisplayMessage dm = new DisplayMessage();
06             dm.ShowMessage();
07         }
08     }
09    
10     public class DisplayMessage
11     {
12         GetMessageFromDatabase Gmd;
13    
14         public DisplayMessage()
15         {
16             Gmd = new GetMessageFromDatabase();
17         }
18         public void ShowMessage()
19         {
20             Console.WriteLine(Gmd.GetMessage());
21             Console.ReadLine();
22         }
23     }
24    
25     public class GetMessageFromDatabase
26     {
27         public string GetMessage()
28         {
29             return "Hi from database";
30         }
31     }
فرض کنید چند وقت دیگه سیستم نیاز پیدا میکنه که پیغام علاوه بر دیتابیس از یک فایل XML هم خونده بشه.
کد:
01    public void ShowMessage()
02           {
03               if (source.ToUpper() == "DATABASE")
04               {
05                   GetMessageFromDatabase Gmd = new GetMessageFromDatabase();
06                   Console.WriteLine(Gmd.GetMessage());
07                   Console.ReadLine();
08               }
09               else if (source.ToUpper() == "XML")
10               {
11                   GetMessageFromXML Gmx = new GetMessageFromXML();
12                   Console.WriteLine(Gmx.GetMessage());
13                   Console.ReadLine();
14               }
15              
16           }
چند وقت دیگه هم نیاز به خوندن از فایل متنی و…
چیزی که مشخصه وابسته بودن کلاس DisplayMessage به جایی که پیغام از اون میاد هست و این یعنی نقض اصل Dependency inversion.
و اما برای رفع این مشکل از اینترفیس استفاد میکنیم. کلاس های GetMessageFromDatabase  و GetMessageFromXML و … هم این اینترفیس رو پیاده سازی میکنن.
کد:
1    public interface IGetData
2        {
3            string GetMessage();
4        }
کلاس DisplayMessage رو هم به شکل زیر تغییر میدیم
کد:
01    public class DisplayMessage
02        {
03            IGetData IGLocal;
04    
05            public DisplayMessage(IGetData IG)
06            {
07                IGLocal = IG;
08    
09            }
10            public void ShowMessage()
11            {
12                Console.WriteLine(IGLocal.GetMessage());
13    
14            }
15        }
نحوه فراخوانی هم بشکل زیر میشه
کد:
01    static void Main(string[] args)
02            {
03                IGetData IG;
04    
05                string source = args[0].ToString();
06    
07                if (source.ToUpper() == "DATABASE")
08                {
09                    IG = new GetMessageFromDatabase();
10                }
11                else if (source.ToUpper() == "XML")
12                {
13                    IG = new GetMessageFromXML();
14                }
15                else if (source.ToUpper() == "TEXT")
16                {
17                    IG = new GetMessageFromTextFile();
18                }
19                else
20                {
21                    IG = new GetMessageFromDatabase();//default set to database
22                }
23    
24                DisplayMessage dm = new DisplayMessage(IG);
25                dm.ShowMessage();
26    
27    
28            }

منبع
[عکس: <a href=www.Mojsazan.com.gif]" class="mycode_img" />
پاسخ
سپاس شده توسط مهدی ابراهیمی ، engineer
#6
سلام لطفا تفاوت ioc و DI را نیز بیان کنید مچکرم
پاسخ
سپاس شده توسط
#7
با سلام خدمت شما دوست عزیز

IOC یک تکنیک برنامه نویسیه  که میگوید کوپلینگ شی (‏میزان اتکای یک ماژول از برنامه به سایر ماژولها  ) در زمان اجرا به وسیله  assembler object محدود بشه که در زمان کامپایل شناخته نمیشود (با static analysis کار میکنه)

همانطور که میدانید در شی گرایی ما چندین نوع روش برای اجرای IOC داریم

مثلfactory pattern یا service locator pattern یا contextualized lookup که یکی از آشنا ترین انها dependency injection است که برای مثال میتوانیم به constructor injection و setter injection و interface injection اشاره کنیم

امیدوارم مفید بوده باشه موفق باشید
[عکس: <a href=www.Mojsazan.com.gif]" class="mycode_img" />
پاسخ
سپاس شده توسط مهدی ابراهیمی
#8
با سلام خدمت همه دوستان عزیز

یکی از دوستان عزیز به نام آقای پویان مهر پرور
چند سال پیش روی DI pattern و کاربردهاش و مقایسه اون با روش های دیگه به عنوان پروژه نهایی دوره لیسان کار میکردن. اون موقع یعنی سال 89 هیچ مطلب فارسی ای در این زمینه نبود. ایشان لطف کردن document پروژه را برای  فروم  ارسال کردن تا کسایی که حوصله خوندن مطالب انگلیسی را ندارن حداقل با خوندن این فایل کمی با موضوع آشنا شن و دیدشون نسبت به طراحی و کد نویسی عوض شه و تو پروژه هاشون استفاده کنن.
ایشان تاکید کردن
 با توجه به وقت کمی که اون موقع در نگارش پایان نامه داشتن، سعی کردن خیلی ساده و جمع و جور بنویسند. ولی خیلی سخت بوده چون مفاهیم پایه لازم بود ه آورده بشه تا مطلب خوب جا بیفته. همانطور که میدانید نوشتن مطالب فنی کامپیوتر اونم به زبان فارسی فاجعه است. دانشگاه ها  هم که همه اش تاکیید میکنن که از معادل فارسی لغات استفاده کنید. اما در کل  ایشان فکر میکنند  فصل 2 اون خوب از کار دراومده باشه انشالله دوستان دیگر هم مثل ایشان به نشر دانش کمک کنند

با تشکر از ایشان

لینک دانلود
[عکس: <a href=www.Mojsazan.com.gif]" class="mycode_img" />
پاسخ
سپاس شده توسط مهدی ابراهیمی ، علیرضا حر


موضوعات مشابه ...
موضوع نویسنده پاسخ بازدید آخرین ارسال
Question انتخاب یک زبان جامع برنامه نویسی موبایل - اپلیکیشن - وب - هوش digicom 19 21,899 08-25-2013, 07:10 PM
آخرین ارسال: مهدی ابراهیمی
  راهنمای کامنت گذاری در زبان های کامپیوتری مهرداد عباسی 1 3,147 01-21-2013, 07:08 PM
آخرین ارسال: مهرداد عباسی
  کدام زبان برنامه‌ نویسی را یاد بگیریم؟ (راهنمای انتخاب زبان برنامه نویسی) مهرداد عباسی 0 3,494 09-22-2012, 07:06 PM
آخرین ارسال: مهرداد عباسی
  تاریخچه زبان های برنامه نویسی مهرداد عباسی 0 2,411 09-20-2012, 11:08 PM
آخرین ارسال: مهرداد عباسی
  مقایسه بین دو زبان برنامه نویسی؟ rector 6 7,814 08-14-2012, 03:10 PM
آخرین ارسال: kakolokia
  زبان برنامه نویسی محبوب دنیا در سال ۲۰۱۲ مهرداد عباسی 0 2,698 08-02-2012, 10:52 PM
آخرین ارسال: مهرداد عباسی
  انتخاب یک زبان C++ یا C# کدام بهتر است؟ alamdar_313 27 32,498 05-03-2012, 04:41 PM
آخرین ارسال: مهرداد عباسی
  رتبه زبان های برنامه نویسی (بازگشت C به رتبه اول) مهرداد عباسی 4 6,035 05-02-2012, 11:25 PM
آخرین ارسال: مهرداد عباسی
  پند‌هایی از ده توسعه‌دهنده حرفه‌ای و بزرگ زبان PHP مهرداد عباسی 0 2,898 06-28-2011, 03:30 PM
آخرین ارسال: مهرداد عباسی
  كدام زبان برنامه ‌نویسی را انتخاب كنیم؟ مهرداد عباسی 0 2,896 12-16-2009, 01:55 AM
آخرین ارسال: مهرداد عباسی

پرش به انجمن:


کاربران در حال بازدید این موضوع: 1 مهمان