معرفی IoC, DIP, DI ,IoC Container و نحوه استفاده از آنها در کار واقعی.
آیا با اصطلاحات زیر آشنا هستید ؟
اغلب اوقات توسعه دهندگان مبتدی با مشکلاتی در درک تفاوت های DIP، IoC، DI و IoC Container مواجه می شوند. آنها همه را با هم قاطی می کنند !!! و تشخیص تفاوت بین آنها دشوار است و نمی دانند چرا باید از آنها استفاده کنند. از سوی دیگر، بسیاری از افراد بدون اینکه بدانند چه مشکلی را حل می کند از DI، IoC استفاده می کنند.
در اینجا، با استفاده از مثالهای ساده و واقعی در مورد هر اصطلاح یاد خواهید گرفت . قبل از اینکه جلوتر بروید، مهم است که تفاوت بین اصل (Principle) و الگو (Design Pattern)را درک کنید.
در مهندسی نرم افزار، اصل طراحی و الگوی طراحی یکسان نیست.
اصل طراحی
اصول طراحی دستورالعمل های سطح بالایی را برای طراحی برنامه های نرم افزاری بهتر ارائه می دهد. آنها دستورالعمل های پیاده سازی را ارائه نمی دهند و به هیچ زبان برنامه نویسی مقید نیستند. اصول SOLID یکی از محبوب ترین مجموعه اصول طراحی است.(بیشتر بخوانید : اصول طراحی نرم افزار Software Design Principles)
به عنوان مثال، اصل SRP از اصول SOLID پیشنهاد می کند که یک کلاس باید تنها یک دلیل برای تغییر داشته باشد. این یک عبارت سطح بالایی است که می توانیم هنگام طراحی یا ایجاد کلاس ها برای برنامه خود در نظر داشته باشیم. SRP مراحل پیاده سازی خاصی را ارائه نمی دهد، اما این به شما بستگی دارد که چگونه SRP را در برنامه خود پیاده سازی کنید.
به عبارتی دیگر اصل می گوید چه چیزی درست است و چه چیزی نادرست. به ما نمی گوید که چگونه یک مشکل را حل کنیم. این فقط دستورالعمل هایی را ارائه می دهد تا بتوانیم نرم افزار خوبی طراحی کنیم و از طراحی بد جلوگیری کنیم
الگوی طراحی
Design Pattern راهحلهای سطح پایین مربوط به پیادهسازی و مشکلات شیگرای رایج را ارائه میکند. در واقع، پیاده سازی خاصی را برای مشکل برنامه نویسی شی گرا خاص پیشنهاد می کند. به عنوان مثال، اگر می خواهید کلاسی ایجاد کنید که در آن واحد فقط یک شیء داشته باشد، می توانید از الگوی طراحی Singleton استفاده کنید که بهترین راه را برای ایجاد کلاسی که فقط می تواند یک شیء داشته باشد، پیشنهاد می کند.
الگوهای طراحی توسط دیگران آزمایش شده اند و پیروی از آنها توصیه می شود، به عنوان مثال.
Abstract Factory و Factory و Singleton و Command
به عبارت دیگر الگو یک راه حل کلی قابل استفاده مجدد برای یک مشکل رایج در یک زمینه معین در طراحی نرم افزار است.
حالا بیایید اصلاحاتی که در ابتدا آمده اند را بفهمیم. شکل زیر اصول یا الگو بودن آنها را مشخص می کند.
همانطور که در شکل بالا نشان داده شده است، IoC و DIP اصول طراحی سطح بالایی هستند (Principle) که باید در طراحی کلاس های برنامه مورد استفاده قرار گیرند. از آنجایی که آنها اصول هستند، بهترین روشها را توصیه میکنند اما جزئیات اجرایی خاصی ارائه نمیدهند. تزریق وابستگی (DI) یک الگو و IoC container یک چارچوب (Framework) است.
بیایید قبل از پرداختن به جزئیات، مروری بر هر اصطلاح داشته باشیم.
Dependency Inversion Principle (DIP)
اصل DIP به تفضيل در اين لينک توضيح داده شده است (پیشنهاد می کنیم قبل از ادامه دادن حتما آن را مطالعه کنید) اما به طور خلاصه و در دو بخش تعريف مي شود :
یک : کلاس های سطح بالا(High-Level) نباید به کلاس های سطح پایین(Low-Level) وابسته باشند. هر دو باید به انتزاعات بستگی داشته باشند.
دو : انتزاع ها نباید به جزئیات بستگی داشته باشند. جزئیات باید به انتزاعات بستگی داشته باشد.
Inversion of Control
این اصل می گوید که انواع مختلفی از کنترل ها در طراحی شی گرا به صورت معکوس در آیند تا بتوان Loose Coupling را بین کلاس های برنامه به دست آورد.
منظور از کنترل در تعریف بالا چیست ؟ کنترل ها به مسئولیت های اضافی یک کلاس، به غیر از مسئولیت اصلی آن، اشاره دارد.
به زبان ساده تر این بیان می کند که یک کلاس نباید وابستگی های خود را به صورت ایستا پیکربندی کند، بلکه باید توسط کلاس دیگری از خارج پیکربندی شود.
با IoC: می توانید «میوه» را بخواهید. هر بار يک ميوه!!! میتوانید میوههای مختلفی دریافت کنید. به عنوان مثال، سیب، پرتقال، یا هندوانه. بنابراین، بدیهی است که وقتی انواع را دوست دارید، IoC ترجیح داده می شود.
بدون IoC: شما درخواست "سیب" می کنید، و با هر درخواست فقط سیب به شما ارائه می شود.
وارونگی کنترل IoC این امکان را برای مصرف کننده فراهم می کند که کنترل بیشتری بر نرم افزار داشته باشد. این به آن انعطاف پذیری و آزادی بیشتری برای انتخاب از گزینه های دیگر می دهد.
چگونگی پیاده سازی Inversion of Control
چندین الگوی طراحی اساسی وجود دارد که برای پیاده سازی IoC در برنامه نویسی شی گرا استفاده می شود.
از ميان تمام الگوهای فوق، تزریق وابستگی (DI) پرکاربردترین و محبوترين الگو مي باشد.
الگوی تزریق وابستگی (DI) تماماً در مورد حذف وابستگی ها از کد شما است.
هدف DI این است که کد قابل نگهداری باشد.
در مهندسی نرمافزار، تزریق وابستگی(dependency injection) تکنیکی است که در آن یک شی(object)، اشیاء دیگری را دریافت میکند که به آنها وابسته است، به نام وابستگی(dependencies). به طور معمول، شی دریافت کننده کلاینت(client) نامیده می شود و شیء منتقل شده ("تزریق شده/injected") سرویس(service) نامیده می شود. کدی که سرویس را به کلاینت ارسال می کند، تزریق کننده(injector) نامیده می شود. به جای اینکه کلاینت مشخص کند از کدام سرویس استفاده خواهد کرد، تزریق کننده به کلاینت می گوید از چه سرویسی استفاده کند. "تزریق" به انتقال یک وابستگی (یک سرویس) به کلاینت که از آن استفاده می کند، اشاره دارد.
سخت شد !!! بیایید قبل از اینکه بفهمیم در برنامه نویسی به چه معناست، ابتدا ببینیم به طور کلی به چه معناست زیرا به ما کمک می کند تا مفهوم را بهتر درک کنیم.
وابستگی به معنای تکیه بر چیزی برای حمایت است. مثلاً اگر بگویم ما بیش از حد به تلفنهای همراه متکی هستیم، به این معنی است که ما به آنها وابسته هستیم.
بنابراین قبل از رسیدن به تزریق وابستگی، ابتدا بیایید بفهمیم که وابستگی در برنامه نویسی به چه معناست.
وقتی کلاس A از برخی عملکردهای کلاس B استفاده می کند، گفته می شود که کلاس A وابستگی به کلاس B دارد.
در سی شارپ، قبل از اینکه بتوانیم از متدهای کلاس های دیگر استفاده کنیم، ابتدا باید شیء آن کلاس را ایجاد کنیم (یعنی کلاس A باید نمونه ای از کلاس B ایجاد کند).
بنابراین، به انتقال وظیفه ایجاد شی به دیگری و استفاده مستقیم از وابستگی، تزریق وابستگی می گویند.
یک کلاس باید بر انجام مسئولیت های خود تمرکز کند نه بر ایجاد اشیایی که برای انجام آن مسئولیت ها نیاز دارد. و اینجاست که تزریق وابستگی وارد عمل می شود: اشیاء مورد نیاز را در اختیار کلاس قرار می دهد.
اساساً سه نوع تزریق وابستگی وجود دارد:
IoC containers
خوب IoC Container (با نام مستعار DI Container) فریم ورکی برای اجرای تزریق وابستگی خودکار است. ایجاد شی و طول عمر آن را مدیریت می کند و همچنین وابستگی هایی را به کلاس تزریق می کند.
ظرف IoC یک شی از کلاس مشخص شده ایجاد می کند و همچنین تمام اشیاء وابستگی را از طریق یک سازنده، یک ویژگی یا یک متد در زمان اجرا (run time) تزریق می کند و در زمان مناسب آن را از بین بردن می برد. این کار به این دلیل انجام می شود که مجبور نباشیم اشیا را به صورت دستی ایجاد و مدیریت کنیم.
همه کانتینرها باید پشتیبانی آسانی را برای چرخه حیات DI زیر ارائه دهند.
کانتینرهای منبع باز یا تجاری بسیاری برای دات نت وجود دارد. برخی از آنها در زیر ذکر شده است.
و اما NET. خود دارای یک DI Container توکار است با نام
Microsoft Dependency Injection Container
وظیفهی DI Container، ایجاد یک نمونه از سرویس درخواست شده، تزریق آن به کلاس درخواست دهنده و در انتها از بین بردن یا Dispose شیء ایجاد شده از سرویس ثبت شده است. بنابراین ما باید در هنگام ثبت سرویس، بر اساس تحلیل و نیاز برنامهی خودمان، طول عمر سرویس(Service Life Time) را مشخص کنیم.
اما در Microsoft Dependency Injection Container و اکثر DI Containerهای دیگر، 3 نوع کلی چرخهی حیات وجود دارند که به ترتیب پایداری و طول عمر شیء ایجاد شده، در زیر آورده شدهاند:
بیشتر بخوانید : بررسی طول عمر سرویس Transient, Singleton & Scoped
بیشتر بخوانید : نقشه راه توسعه دهندگان Asp.net Core