تزریق وابستگی (DI) مفهومی آسان برای درک نیست و استفاده از آن در برنامه های جدید یا موجود حتی گیج کننده تر است. جس اسمیت به شما نشان می دهد که چگونه می توانید تزریق وابستگی را بدون ظرف تزریق در زبان های برنامه نویسی C# و Java انجام دهید. در این مقاله، نحوه پیاده سازی تزریق وابستگی (DI) در برنامه های دات نت و جاوا را به شما نشان می دهم. مفهوم تزریق وابستگی برای اولین بار در سال 2000 مورد توجه توسعه دهندگان قرار گرفت، زمانی که رابرت مارتین مقاله "اصول و الگوهای طراحی" را نوشت (که بعدها با نام مخفف SOLID شناخته شد ). D در SOLID به وابستگی وارونگی (DOI) اشاره دارد که بعداً به عنوان تزریق وابستگی شناخته شد. اصلی ترین و رایج ترین تعریف: وارونگی وابستگی وارونگی روشی است که یک کلاس پایه وابستگی ها را مدیریت می کند. مقاله اصلی مارتین از کد زیر برای نشان دادن وابستگی یک کلاس Copyبه یک کلاس سطح پایین استفاده کرد WritePrinter:
اولین مشکل آشکار این است که اگر لیست پارامترها یا انواع یک متد را تغییر دهید WritePrinter، باید هر جا که وابستگی به آن متد وجود دارد، بهروزرسانیها را اجرا کنید. این فرآیند هزینه های نگهداری را افزایش می دهد و منبع بالقوه ای برای خطاهای جدید است.
مشکل دیگر: کلاس Copy دیگر کاندیدای بالقوه برای استفاده مجدد نیست. به عنوان مثال، اگر بخواهید کاراکترهای وارد شده از صفحه کلید را به جای چاپگر به یک فایل خروجی دهید، چه؟ برای انجام این کار، می توانید کلاس را Copyبه صورت زیر تغییر دهید (سینتکس زبان C++):
علیرغم معرفی یک وابستگی جدید WriteDisk، وضعیت بهبود نیافت (بلکه بدتر شد) زیرا اصل دیگری نقض شد: "موجودات نرم افزاری، یعنی کلاس ها، ماژول ها، توابع و غیره، باید برای گسترش باز باشند، اما بسته شوند برای تغییر." مارتین توضیح می دهد که این عبارات شرطی if/else جدید ثبات و انعطاف کد را کاهش می دهد. راه حل این است که وابستگی ها را معکوس کنیم تا روش های نوشتن و خواندن به Copy. بهجای اینکه وابستگیها «popping» شوند، از سازنده عبور میکنند. کد اصلاح شده به شکل زیر است:
اکنون کلاس را Copyمی توان به راحتی با پیاده سازی های مختلف متدهای کلاس Readerو Writer. کلاس Copyهیچ اطلاعاتی در مورد ساختار داخلی انواع Readerو Writer, امکان استفاده مجدد از آنها با پیاده سازی های مختلف را ندارد. اما اگر همه اینها به نظر شما نوعی گول زن است، شاید مثال های زیر در جاوا و سی شارپ وضعیت را روشن کند.
مثال در جاوا و سی شارپ
برای نشان دادن سهولت تزریق وابستگی بدون محفظه وابستگی، اجازه دهید با یک مثال ساده شروع کنیم که میتواند برای استفاده DIدر چند مرحله سفارشی شود. فرض کنید کلاسی داریم HtmlUserPresentationکه وقتی متدهای آن فراخوانی می شود، یک رابط کاربری HTML ایجاد می کند. در اینجا یک مثال ساده آورده شده است:
هر پروژه ای که از این کد کلاس استفاده می کند، وابستگی به کلاس دارد HtmlUserPresentationکه در نتیجه مشکلات قابلیت استفاده و نگهداری که در بالا توضیح داده شد، می شود. یک بهبود بلافاصله خود را نشان می دهد: ایجاد یک رابط با امضای همه روش های موجود در کلاس HtmlUserPresentation. در اینجا نمونه ای از این رابط را مشاهده می کنید:
پس از ایجاد اینترفیس، کلاس را HtmlUserPresentationبرای استفاده از آن تغییر می دهیم. با بازگشت به نمونه سازی نوع HtmlUserPresentation، اکنون می توانیم از نوع رابط به جای نوع پایه استفاده کنیم:
ایجاد یک رابط به ما این امکان را می دهد که به راحتی از سایر پیاده سازی ها استفاده کنیم IHtmlUserPresentation. برای مثال اگر بخواهیم این نوع را تست کنیم به راحتی می توانیم نوع پایه را HtmlUserPresentationبا نوع دیگری به نام HtmlUserPresentationTest. تغییرات ایجاد شده تا کنون تست، نگهداری و مقیاس کد را آسانتر میکند، اما هیچ کاری برای استفاده مجدد انجام نمیدهد زیرا همه HtmlUserPresentationکلاسهایی که از نوع استفاده میکنند هنوز از وجود آن آگاه هستند. برای حذف این وابستگی مستقیم، می توانید یک نوع رابط را IHtmlUserPresentationبه سازنده (یا لیست پارامترهای متد) کلاس یا متدی که از آن استفاده می کند، ارسال کنید:
سازنده UploadFileاکنون به تمام عملکردهای نوع دسترسی دارد IHtmlUserPresentation، اما چیزی در مورد ساختار داخلی کلاسی که این رابط را پیادهسازی میکند، نمیداند. در این زمینه، تزریق نوع زمانی اتفاق میافتد که نمونهای از کلاس ایجاد شود UploadFile. یک نوع رابط IHtmlUserPresentationبا ارسال پیاده سازی های مختلف به کلاس ها یا روش های مختلف که به عملکردهای متفاوتی نیاز دارند، قابل استفاده مجدد می شود.
نتیجه گیری و توصیه هایی برای تجمیع مطالب
شما در مورد تزریق وابستگی یاد گرفتید و گفته می شود که کلاس ها به طور مستقیم به یکدیگر وابسته هستند زمانی که یکی از آنها نمونه دیگری را برای دسترسی به عملکرد نوع هدف مورد استفاده قرار می دهد. برای جدا کردن وابستگی مستقیم بین این دو نوع، باید یک رابط ایجاد کنید. یک رابط به یک نوع این توانایی را می دهد که پیاده سازی های مختلف را بسته به زمینه عملکرد مورد نیاز شامل شود. با ارسال یک نوع واسط به سازنده کلاس یا متد، کلاس/روشی که به عملکرد نیاز دارد هیچ جزئیاتی در مورد نوع پیادهسازی اینترفیس نمیداند. به همین دلیل، یک نوع رابط را می توان مجدداً در کلاس های مختلف مورد استفاده قرار داد که به رفتار مشابه، اما نه یکسان نیاز دارند.
برای آزمایش تزریق وابستگی، به کد خود از یک یا چند برنامه نگاه کنید و سعی کنید یک نوع پایه پر استفاده را به یک رابط تبدیل کنید.
کلاس هایی را که مستقیماً این نوع پایه را نمونه سازی می کنند برای استفاده از این نوع رابط جدید تغییر دهید و آن را از طریق سازنده یا لیست پارامترهای متد کلاسی که از آن استفاده می کند عبور دهید.
یک پیاده سازی آزمایشی برای آزمایش این نوع رابط ایجاد کنید. هنگامی که کد شما دوباره ساخته شد، DIپیاده سازی آن آسان تر می شود و متوجه خواهید شد که برنامه شما از نظر استفاده مجدد و قابلیت نگهداری چقدر انعطاف پذیرتر می شود.
GO TO FULL VERSION