nader marandi
nader marandi
خواندن ۳ دقیقه·۵ سال پیش

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

شاید این اصطلاح بارها به گوشتون خورده باشه و جاهای مختلف در موردش خونده باشید. می خوام اینجا یک مثال از استفادش رو برای فهم بهتر توضیح بدم.

این اصطلاح توسط رابرت مارتین (Robert Martin) به این شکل بیان می شود:

high level modules should not depend on low level modules; both should depend on abstractions. Abstractions should not depend on details.  Details should depend upon abstractions.

الف: ماژول‌های سطح بالا نباید به ماژول‌های سطح پایین وابسته باشند. هر دوی آن‌ها (ماژول‌های سطح بالا و پایین) باید به Abstraction‌ها وابسته باشند.
ب: Abstraction‌ها نباید به جزئیات وابسته باشند. جزئیات باید به Abstraction‌ها وابسته باشند.

مثال

سال ها قبل وقتی دستگاه های ATM بوجود اومدن، شرکت های زیادی بودن که قسمت های مختلف اون رو تولید می کردند. یک شرکت X بود که این قطعات رو می خرید و اسمبل می کرد و یک ATM می ساخت. این شرکت ی برنامه نویس داشت به اسم Joe که برنامه ای می نوشت که از تمام قسمت های ATM استفاده می کرد و به مشتریان خدمات می داد. یکی ازین قسمت ها پول شمار بود. روز اولی که شرکت X شروع به کار کرده بود، فقط شرکت P1 این دستگاه رو تولید می کرد و برای همین از اونها این دستگاه رو خریداری کردند. شرکت P1 دستگاه پول شمارشون رو به همراه یک درایور با API خودشون میفروختن که اون API به شکل زیر بود:

void give_money(int money_toman);

وقتی مشتری به برنامه Joe می گفت که نیاز به 1000 تومن پول داره، Joe هم تابع بالا رو صدا می کرد و دستگاه پول شمار 1000 تومن به مشتری تحویل می داد. یک مدت که گذشت، شرکت X مجبور شد از شرکت P2 هم این دستگاه رو خریداری کنه(قیمت ارزونتر یا عدم تولید توسط شرکت P1). شرکت P2 هم دستگاه پول شمارشون رو به همراه یک درایور با API خودشون میفروختن که اون API به شکل زیر بود:

void give_money_to_client(int money_rial);

void pause();

void resume();

این اتفاق بارها افتاد و هربار شرکت Joe از یک شرکت دیگه ای پول شمار رو تأمین می کرد. Joe هم هر بار یک adapter رو API جدید می نوشت و اون رو تبدیل به API شرکت P1 می کرد، تا خیلی قسمت های مختلف کدش رو تغییر نده.(شاید بعضی از ما ها همین کارم نکنیم و کلی کدمون رو تغییر بدیم)

void give_money(int money_toman) { give_money_to_client(money_toman*10); }

یک مدت که گذشت Joe خسته شد و به چند تا از دوستاش که مثل خودش تو این کار بودن تماس گرفت و دید که اونا هم همین مشکل رو دارند. با هم جلسه گذاشتن و به این نتیجه رسیدن که اعتصاب کنن و خودشون بگن که API مورد نیازشون چه شکلی هست و تمام شرکت های تولید کننده رو مجبور کنند اون API پیاده سازی کنند. شرکت های تولید کننده ATM هم از ایده برنامه نویساشون خوششون اومد و ازشون حمایت کردند و ایده اونها رو استاندارد کردند(WOSA/XFS) و اون رو شامل تمام دستگاه هایی کردن که در ساخت ATM استفاده می شد. اینجوری بود که وابستگی وارونه شد. به جای اینکه Joe به API تولید کننده های دستگاه وابسته بشه، تولید کننده ها بودن که به API ای که Joe نیاز داشت وابسته شدن.

توضیحات بالا در مورد قسمت الف اصل وارونگی وابستگی بود. در مورد قسمت ب اگر به API شرکت P1 و P2 نگاه کنید، شرکت P2 دوتا تابع بیشتر داشت که این بخاطر feature اضافه ی دستگاهش بود. اصل کار دستگاه پول شمار، شمارش پول و تحویل اون به مشتری هستش. در نتیجه این دوتابع اضافه، بودنشون در API باعث وابسته شدن به جزئیات میشه و میشه اونها رو حذف کرد.

پیشنهاد

همیشه وقتی می خواید ی سیستم بزرگ طراحی کنید، قسمت هایی که ممکنه در طول عمر سیستم تغییرات داشته باشند رو پیدا کنید و برحسب عملکردشون یک interface براشون تعریف کنید و اگر اون قسمت دست خودتون نبود و تغییرات داشت می تونید از adapter استفاده کنید. تا جایی که می تونید جزئیات رو وارد interface نکنید و اگر وارد شد قابلیتی بذارید که بشه فهمید آیا اون جزء عملکردش وجود داره یا نه.

مثلا فرض کنید که دارید برای انواع موبایل ها کد میزنید و یک سری از موبایل ها GPS دارند ولی یک سری هم ندارند. اگر جزئیات استفاده از GPS وارد کدتون شد، می تونید داخل توابعی که از GPS استفاده می کنند اگر این قابلیت وجود نداشت exception یا کد خطای مناسب بدهید و همچنین یک تابع برای این که آیا GPS وجود دارد یا نه اضافه کنید.

bool have_gps();
without DIP
without DIP
with DIP
with DIP


soliddependency inversion principleprogramming
شاید از این پست‌ها خوشتان بیاید