تزریق وابستگی یا همون Dependency Injection تو نود.جی‌اس

یه مفهوم خوب که اگه بتونی درست پیاده سازیش بکنی، می ارزه. ولی اگه نتونی درست پیاده سازیش بکنی به یه سکه سیاه هم نمی‌ارزه
یه مفهوم خوب که اگه بتونی درست پیاده سازیش بکنی، می ارزه. ولی اگه نتونی درست پیاده سازیش بکنی به یه سکه سیاه هم نمی‌ارزه

شاید بحث DI در ابتدا سخت به نظر برسه ولی اینطور نیست.

مثالی واقعی از DI

ما یه ماشین (کلاس Limousine) داریم. این ماشین به اجزای دیگه خودش مثل موتوریتش، لامپ هاش، چرخ هاش و ... وابستگی داره (کلاس های Engine و ...) حالا شما فرض کن که بین این وابستگی ها و ماشین وابستگی شدید (tight coupled) وجود داره.

پس عملا هر تغییری توی پیاده سازی وابستگی ها تاثیر مستقیم روی ماشین (کلاس Limousine) داره. راه حل چیه؟ اینه که توی ماشین به صورت مستقیم از وابستگی ها استفاده نکنیم. بلکه بیاییم وابستگی ها رو به یه واسط وصل بکنیم و بعد اون واسط رو همه جا استفاده بکنیم.

به این صورت استفاده می‌کنیم که پیاده سازی اون واسط باید با توجه به نوع ماشین فرق بکنه. یعنی فرض حالا ماشین ون میخوای. باید چکار بکنی؟ پیاده سازی ماشین (کلاس Limousine) رو عوض بکنی؟ بعدش تازه بیای پیاده سازی وابستگی ها رو هم عوض بکنی؟

احتمالا جوابت نه هست. پس میایم یه ماشین جدید (کلاس Van) میسازیم که نوع پیاده سازی اون واسط توش فرق داره (ویژگی های اضافه ای داره، پیاده سازی کلاس هایی که بهش وابسته هستن فرق داره (Engine و ...) یسری چیزا رو کمتر داره). به این صورت بدون اینکه لازم باشه به کلاس های وابسته یا کلاس Limousine دست بزنیم یه کلاس جدید ساختیم.



توضیحات فنی

  • تزریق وابستگی یعنی هندل کردن وابستگی ها خارج از کلاس
  • یه روش، یه تکنیک، یه pattern توی مهندسی نرم افزار.
  • گرفتن یه آبجکت و وارد کردن آبجکت های وابسته‌ی اون آبجکت بهش.
  • روشی برای جدا سازی کامپوننت های مستقل نرم افزار.
  • روش وارد کردن dependency های یه کلاس به اون کلاس بجای استفاده مستقیم (require کردنشون).
  • اون آبجکت های وابسته رو Dependency میگن.
  • یه روش برای تغییر دادن پیاده سازی یه instance از یه کلاس بدون اینکه سایر instance ها رو تحت تاثیر قرار بدی.
  • تعریف اینترفیس و پیاده سازی اون اینترفیس

دو نوع وابستگی داریم:

  1. وابستگی کم (loosely coupled)
  2. وابستگی زیاد (tight coupled) = انعطاف پذیری کم نرم افزار، رابطه باینری بین کلاس ها، چفت شدن کلاس های وابسته به هم

اصل وارونگی وابستگی (Dependency Inversion Principle - DIP)

کلاس های سطح بالا به کلاس های سطح پایین وابسته نباشن. انتزاع نباید به جزئیات وابسته باشه. یه کلاس اصلی تعریف بکنید که از یه کلاسی inherit میشه. بعد تو کلاس parent بیاید DI رو انجام بدید.

روش های DI

  1. روش Constructor injection: در این روش instance کلاس سطح پایین (وابستگی) به سازنده کلاس سطح بالا ارسال میشه.
  2. روش Method injection: در این روش یه instance از کلاس سطح پایین به متد کلاس سطح بالا ارسال میشه.

نکته: وقتی میخوای کلاس testable بنویسی باید اون کلاس کاملا ایزوله باشه. پس اگر برنامه نویسی TDD میخوای بری باید DI بنویسی.



نود.جی‌اس و module pattern

یه بحثی دیدم که میگن چونکه نود.جی‌اس module pattern هست شما میتونی از پیاده سازی DI صرف نظر بکنی (توی نود.جی‌اس به خاطر require ما به DI نیاز نداریم) ولی DI یسری مزایای دیگه هم داره که باعث میشه پیاده بکنیش.

توی DI ما بجای require کردن یا ساختن instance میایم وابستگی ها رو به صورت dependency به ماژول وارد می‌کنیم.

این مدل پیاده سازی کلاس مطابق با DI نیست.

const Config = require('./config');

class SendSMS {
  constructor() {
    let conf = new Config(/* arguments comes here */);
    this._gateway = new Gateway(conf);
  };
  send(msg) {
    this._gateway.send(msg);
  };
};

ویرایش شده اون به این شکل میشه

class SendSMS {
  constructor(gateway) {
    this._gateway = gateway;
  };
  send(msg) {
    this._gateway.send(msg);
  };
};



ویرایش جدید توی سال ۱۴۰۰

بر اساس تجارب من توی سال ۱۳۹۹ به این نتیجه رسیدم که Dependency injection توی نود.جی‌اس و جاوااسکریپت هم باید داشته باشیم به همین خاطر پیشنهاد من NestJS هست.