صنایع فناوری طراحان بهینه

مقدمه ای بر تزریق وابستگی ها Dependency Injection

مقدمه ای بر تزریق وابستگی ها Dependency Injection

مقدمه ای بر تزریق وابستگی ها و قواعد آن



برای درک بهتر این مطلب بهتر است با این مفاهیم آشنایی داشته باشید:


  • اشنایی کافی با مفاهیم پایه در C#
    •  سازنده ها Constructors
    • خواص یا ویژگی کلاس Properties
    • انقیاد داده ها Data Binding
  • درک درستی از اینترفیس ها Interfaces
    • اینترفیس ها در سی شارپ کمک می کند تا کد هایی قابل نگه داری Maintainable و توسعه Extensible و قابل تست Easily testable نوشت. 
    • یک اینترفیس دربرگیرنده تعریف یک گروه از عملکرد های Functionality مرتبط به هم است که یک کلاس Classیا ساختار Struct می تواند آن را پیاده سازی کند

تزریق وابستگی ها Dependency Injection چیست ؟ 

تزریق وابستگی ها یک الگوی طراحی نرم افزار است که با ما امکان می دهد که در زمان کامپایل و هم چنین زمان اجرا انتخاب کنیم که چه کامپوننت های بایستی ساخته شده و مورد استفاده قرار گیرند.

 

ویکی پدیا سال 2012

Dependency injection is a software design pattern that allows a choice of component to be made at run-time rather than compile time.

 

تزریق وابستگی ها یک الگوی طراحی نرم افزار است که به ما امکان می دهد وابستگی های هارد کد شده را حذف کرده و بتوانیم در زمان کامپایل و اجرا این وابستگی ها را تغییر دهیم.

 

ویکی پدیا 2013

Dependency injection is a software design pattern that allows the removal of hard-coded dependencies and makes it possible to change them, whether at run-time or compile-time.

 

Mark Seeman

تزریق وابستگی ها مجموعه ای از قوانین و الگو های طراحی نرم افزار است که ما را برای توسعه کدی با همبستگی پایین توانمند می سازد


Dependency Injection is a set of software design principles and patterns that enable us to develop loosely coupled code.

 Image title


آقای مارک سیمن کتابی با نام Dependency Injection in .NET  تالیف کرده اند. کامل ترین و اصلی ترین هدف تزریق وابستگی ها را مارک سیمن بیان کرده است.

در واقع ما با تزریق وابستگی ها به دنبال توسعه کدی هستیم که کمترین وابستگی را در خود داشته باشد.

چرا بایستی کد همبستگی پایینی داشته باشد؟

  • توسعه پذیری Extensibility  : با افزودن یک کلاس به برنامه نیازمند تغییرات در بخش های دیگر نباشیم
  • قابلیت تست پذیری Testability : فرآیند تست واحد به سهولت و بدون نیاز به در نظرگرفتن بخش های دیگر در آزمون انجام گیرد
  • انقیاد پویا Late Binding : بتوان در زمان اجرا و کامپایل خدمات مورداستفاده برنامه را تغییر داد
  • توسعه موازی  Parallel Development : توسعه یک بخش از برنامه منوط به توسعه بخش خاص دیگری نباشد
  • قابلیت نگه داری Maintainability : افزودن بخش های جدید به برنامه و تغییرات پرهزینه نشوند


مفاهیم تزریق وابستگی ها

  • الگو های طراحی Patterns
    • تزریق سازنده Constructor Injection
    • تزریق ویژگی Property Injection
    • تزریق متد یا روال Method Injection
    • Ambient Context
    • Service Locator
  • Object Composition
    • Composition Root
  • DI Containers
    • Unity, Ninject, Castle Windsor, Autofac, StructureMap, Spring.NET


لایه های برنامه Application Layering

 

با توجه به اینکه در معماری سنتی لایه ای هرلایه از یک Instance از لایه پایین تر خود برای دریافت خدمات لایه پایین استفاده می کند در نتیجه به شکل سلسله مراتبی هر لایه به لایه پایین تر از خود وابسته است و در نتیجه بالاترین لایه یعنی View نیز به پایین ترین لایه یعنی لایه Service وابسته است.

هم چنین در صورتی که بخواهیم برنامه از چند بانک مختلف استفاده کنیم مجبوریم که طی یک سوییچ بر اساس تنظیماتی که ذخیره شده کانکشن جاری برنامه را مشخص کنیم و این کار در لایه Presentation بایستی انجام گیرد درحالی که مسولیت این لایه نیست هم چنین در صورتی که یک بانک جدید بخواهیم اضافه کنیم یا مثلا فرآیند Caching به برنامه اضافه کنیم هم بخش Repository  تغییر خواهد کرد و هم بخش Presentationهم چنین برای Unit Testing برای تست بخش View بایستی کلیه لایه ها اجرا شوند تا بتوان بخش View را تست کرد و موجب انتشار خطا در کلیه لایه ها می شود.درحالی که اصل اول الگوی SOLID  بر این تاکید دارد که هر کلاس بایستی مسولیتحداکثریک کار را به عهده بگیرد، در حالی که مسولیت بخش Repository  در اینجا به بخش Presentation نیز داده شده است.


Image title


وابستگی محکم Tight Coupling


در این ساختار لایه View مسئولیت دریافت اطلاعات در قالب ViewModel از لایه Presentation را دارد.

لایه View مسئول ایجاد و مدیریت ViewModel است

در لایه presentation ماژول نگه داری اطلاعات همان ViewModel یک ارتباط Concrete به لایه Repository دارد

ViewModel مسول ایجاد و مدیریت Repository می باشد

در لایه Repository نیز یک ارتباط Concrete به لایه سرویس Service وجود دارد.


لایه Repository مسول ایجاد و مدیریت Service می باشد

البته این یک مثال است و این وابستگی آنچنان هم بد نیست ولی قابل بهبود است.

سناریو Different Repository

اکنون فرض کنید چندین انتخاب option برای ارتباط با بانک داریم:

  • افزودن انتخاب SQl Server برای ارتباط با بانک
  • افزودن انتخاب استفاده از CSV فایل جهت نگه داری اطلاعات
  • افزودن بستر ایجاد کانال های جدید جهت نگه داری اطلاعات در آینده
  • طبیعتا بایستی لایه presentation مسئول استفاده و تنظیمات برای انتخاب های موجود در اربتاط با بانک باشد. ساده ترین روش استفاده از یک ساختار Switch Case و خواندن انتخاب مورد نظر از فایل Config برنامه است و به تناسب کانفیگ موجود سرویس Repository مورد نیاز استفاده می شود.

سناریو دیگر  Client-Side Caching و یا سناریو تست است که بایستی از هرکدام از لایه های Service و Repository نمونه های را برای تست استفاده کرد.

سوال اصلی : چه کسی مسئول ایجاد Repository است؟

طبق اصل اول اصول چهارگانه S.O.L.I.D Principles ، یعنی اصل Single Responsibility هر کلاس بایستی یه یک دلیل تغییر کند و آن هم با داشتن یک مسئولیت میسر است.

مسئولیت ViewModel کنترل لایه Presentation است و نباید مسئولیت انتخاب Repository را نیز به عهده داشته باشد در نتیجه نباید برای افزودن یک Repository جدید مجبور به تغییر ViewModel نیز شویم.

راه حل : کاهش وابستگی Loose Coupling

تزریق وابستگی مجموعه ای از قواعد و اصول طراحی نرم افزار است که ما را قادر به توسعه کدی با وابستگی پایین می سازد.

در صورتی که کلاس یا لایه بالاتر به جای دریافت یک شی از نوع کلاس یا لایه پایین تر، یک Interface که الگوی طراحی کلاس های لایه پایین تر را معرفی می کند بگیرد، می تواند فارغ از اینکه جزییات پیاده سازی لایه پایین تر چیست یا اینکه در زمان اجرا کدام کلاس لایه پایین تر مورد استفاده قرار می گیرد تنها با استفاده از الگو از لایه پایین استفاده کند. در واقع با استفاده از Interface کلاس های خود را Pluggable می کنیم:

Image title

این اینترفیس در سازنده لایه بالا تر دریافت خواهد شد، الگوی طراحی  Constructor Injection در واقع با استفاده از این الگو وظیفه تعیین نوع را به عهده واحد دیگری گذاشته ایم و این انتقال مسولیت تا لایه View انجام می شود، در لایه View می توان به شکل کانفیگ این تنظیمات را خواند و اعمال کرد و هم چنین فریم ورک هایی برای انجام این Mapping بین اینترفیس و نمونه کاربردی از کلاس ها وجود دارند که IoC Container  نامیده می شوند.

هم چنین برای سناریو دیگر که ذکر شد می توان از Repository که خدمات Caching را ارایه می دهد استفاده کرد.

Image title

تست واحد Unit testing

برای پیاده سازی و سود بردن از تست واحد در پروژه های نرم افزاری بایستی شرایط زیر را مهیا کرد:

  • انجام تست به تفکیک بخش های کوچک
    • معمولا این تست بایستی در سطح متد انجام گردد
  • تست درانزوا (محیط محدود)
    • حذف تعامل خارجی با ماژول های دیگر که امکان شکست تست را دارند
    • کاهش تعداد اشیایی که برای اجرای تست مورد نیاز هستند

توجه کنید که هنوز به تست جامعیت نیاز داریم، در تست جامعیت همه این بخش های کوچک در کنار یکدیگر تست می شوند.

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


Dependency Injection Containers

به فرآیند برعکس کردن وابستگی و تزریق آن در جهت مخالف وابستگی Inversion of Control گفته می شود.

پکیج های متنوعی این سرویس را ارایه می دهند که Ioc Container یا DI Container نامیده می شوند.

از جمله این پکیج ها :

  • Unity
    • Microsoft Patterns & Practics
  • Spring.NET
    • .NET Port of the Java Spring Framework
  • Castle Windsor
    • Part of the Castle Project
  • Ninject
  • Autofac
  • StrutureMap
  • Plus, many, many others

مفاهیم قابل بحث در حوزه DI Container ها به شرح زیر است:

  • LifeTime Management
    • Singleton
    • Transient
    • Per Thread
  • Object Resolution
    • تولید اتوماتیک وابستگی ها توسط تزریق سازنده
    • قابل تنظیم با استفاده از Property Injection
  • Late Binding
    • بارگذاری پویا با استفاده از تنظیمات برنامه Configuration
  • Unit Testing with a Container


جهت اطلاعات بیشتر می توانید مراجعه کنید به دوره آموزشی 

Dependency Injection On-Ramp تهیه شده توسط 

Jeremy Clark





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