معکوس سازی وابستگی (Dependency Inversion) در برنامه نویسی

پیش نیاز این درس:

برای درک این مفهوم بایستی در برنامه نویسی شی گرا Interface را بشناسید. همچنین بهتر است دروس ابتدایی دوره SOLID را خوانده باشید.

مدرس: مسعود کاویانی

۱. ماژول های سطح بالا نباید به ماژول های سطح پایین وابستگی داشته باشند. هر دو این ماژول ها باید به یک سطح انتزاعی وابسته باشند.

۲. انتزاع ها نباید به جزئیات وابسته باشند بلکه جزئیات باید به انتزاع ها وابسته باشند

این تعریف اصلی معکوس سازی وابستگی (Dependency Inversion) بود. این اصل پنچمین آخرین حرف کلمه SOLID را نشان میدهد که در دوره SOLID به آن میپردازیم.

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

فرض کنید تکه کدی مانند زیر دارید:

<?php
class Mailer
{
    public function send ($string)
    {
        // sending mail
    }
}

class SendWelcomeMessage
{
    private $mailer;

    public function __construct (Mailer $mailer)
    {
        $this->mailer = $mailer;
    }

    public function send_string ($user_id)
    {
        $string = 'welcome user ' . $user_id;
        $this->mailer->send ($string);
    }
}
?>

در تکه کد بالا یک کلاس SendWelcomeMessage داریم و در آن یک تابع send_string که توسط آن پیغام خوش آمد گویی را برای کاربری با شماره $user_id میفرستد. این کلاس از یک کلاس Mailer استفاده میکند تا بتواند از تابع send آن ایمیل خود را بفرستد. پس الان یک کلاس SendWelcomeMessage داریم که به وسیله آن میتوانیم یک پیغام خوش آمد گویی را برای کاربران ایمیل کنیم.

حال فرض کنید نیازمندی های پروژه عوض می شود و میخواهیم به جای ایمیل کردن این پیام، این پیام را SMS کنیم. قاعدتا بایستی بسیار از قسمت های کد بالا را تغییر داده و کد را دوباره بازنویسی کنیم.

معکوس سازی وابستگی یا همان Dependency Inversion اینجا به کمک ما می آید. توجه کنید که کلاس SendWelcomeMessage به کلاس Mailer وابسته است. که این کار در معکوس سازی وابستگی ها خلاف قانون ماست. پس به تکه کد زیر نگاهی بیندازید:

<?php
Interface Sender
{
    public function send ($string);
}

class Mailer implements Sender
{
    public function send ($string)
    {
        // sending mail
    }
}

class SMSer implements Sender
{
    public function send ($string)
    {
        // sending SMS
    }
}

class SendWelcomeMessage
{
    private $sender;

    public function __construct (Sender $sender)
    {
        $this->sender = $sender;
    }

    public function send_string ($user_id)
    {
        $string = 'welcome user ' . $user_id;
        $this->sender->send ($string);
    }
}
?>

در اینجا عملیات Refactoring انجام داده ایم. یعنی کد را به حالتی بازنویسی کرده ایم که از لحاظ مهندسی نرم افزار بهتر باشد. همان طور که میبینید کلاس SendWelcomeMessage دیگر به کلاس Mailer وابسته نیز در عوض به یک واسط (Interface) به اسم Sender وابسته است. دو کلاس دیگر هم داریم Mailer و SMSer که هر دوی آن ها از نوع Sender هستند. حال هر موقع که بخواهیم میتوانیم به کلاس SendWelcomeMessage بگوییم که از کدام کلاس استفاده کند. در واقع در هنگام ساخت کلاس SendWelcomeMessage میتوانیم یکی از دو کلاس Mailer یا SMSer را به این کلاس بدهیم تا این کلاس به راحتی از آن در فرآیند های خود استفاده کند. یعنی به جای اینکه در هر بار تغییر نیازمندی های برنامه بخواهیم در قسمت های زیادی از کدها دست ببریم، فقط کافیست یک کلاس از نوع واسط Sender بسازیم و در تنظیمات دیگری بگویم که هر بار کلاس SendWelcomeMessage صدا زده شد، یکی از انواع واسط Sender مثلا Mailer را به آن کلاس اختصاص بده.

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

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

اگر به دنبال مثالی شهودی هستید، فرض کنید شما سرآشپز یک رستوران هستید و به آشپز زیردست خود هر روز میگویید که یک خورشت خاص را با گوشت گوسفند درست کند. حال فرض کنید از یک روز به بعد به دلیل گرانی گوشت گوسفند، میخواهید خورشت را با گوشت گوساله درست کنید! پس به آشپز خود میگویید امروز خورشت با گوشت گوساله درست کن. در این حالت اگر بخواهیم از اصل معکوس سازی وابستگی استفاده کنیم، باید هر روز صبح به یک قصاب بگوییم که یک گوشت (گوساله یا گوسفند با توجه به قیمت مناسب آن روز) را بیاورد و در طبقه دوم یخچال قرار دهد. حال هر روز به جای اینکه به آشپز بگوییم خورشت را با فلان گوشت آماده کن، با او یک قرار میگذاریم که خورشت را با گوشت موجود در طبقه دوم یخچال درست کند. یعنی فقط به آشپز میگویم خورشت درست کن. آشپز خودش به سراغ گوشت موجود در طبقه دوم یخچال می رود و هر نوع گوشتی که باشد (گوسفند یا گوساله) را برمیدارد و در خورشت میریزد. به این صورت آشپز دیگر در انتخاب نوع گوشت هر روز به شما وابستگی ندارد و قصاب با توجه به قیمت گوشت، گوشت مورد نیاز شما را در طبقه دوم یخچال قرار میدهد.

منابع این بحث و اطلاعات بیشتر

» تکه کد مروبط به DIP

» وب سایت Codeburst

» وب سایت TutsPlus

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

2 دیدگاه دربارهٔ «معکوس سازی وابستگی (Dependency Inversion) در برنامه نویسی»

  1. سلام، توضیحات کامل و فوق العاده بودن
    فقط ی موردی تو صفحه ی سایت ی المنت دارید که باعث شده scroll-x بخوره:
     

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *