اصل پنجم پیاده سازی SOLID با کدهای دارت برای فریم ورک Flutter

Dependency Inversion Principle
Dependency Inversion Principle

“اصل معکوس سازی وابستگی“ که آنرا “اصل وارونگی وابستگی” هم می نامند برگرفته از عبارات لاتین (Dependency Inversion Principle) یا به طور خلاصه (DIP) ، پنجمین اصل از SOLID است و می گوید که: “ماژول‌های سطح بالا نباید به ماژول‌های سطح پایین وابسته باشند” .

در واقع، ماژول ها به جای دسترسی مستقیم به منابعی که وابستگی ایجاد می کنند (مثلا کلاس ها) ، باید از طریق interface ها، به آنها دسترسی داشته باشند. در این صورت تغییرات کلاس های ما ، توسط interface ها به درون خود کلاس ها محدود می شود و لایه های بالاتر را درگیر تغییر نمی کنند.

در وصف اصل وارونگی وابستگی ، گفته می شود که : اصل وارونگی وابستگی، ترکیبی ناب ، از اصل باز/بسته و اصل جایگزینی لیسکوف است.


برای اینکه مفهوم را در مثال عملی کاملتر متوجه شویم آن را به دو شیوه صحیح و غلط آن پیاده سازی میکنیم.

۱- مثال زیر DIP را نقض می کند.

فرض کنیم که قرار است برای یک فروشگاه کتاب نرم افزاری کتابخوان بسازیم . از ما خواسته شده برای کاربری امکانات زیر را فراهم کنیم:

۱- بخشی از کتاب مدنظر را ببیند.
۲-از نظر سایر کاربران درباره کتاب مطلع شود.
۳- اگر مایل بود، آن کتاب را به لیست کتابهای موجود در کتابخانه خود اضافه کند.

برای شروع کلاس کتاب و کلاس کتابخانه را به صورت زیر پیاده سازی می کنیم:

class Book {
  void seeReviews() {
    // logic book reviews
  }

  void readSample() {
    // logic read book-sample
  }
}

class Library {
  late Book book;
  void addBook(Book book) {
    // logic add book
  }
}

همانطور که مشاهده می کنید کلاس Book به ما اجازه خواندن sample و مشاهده review های کتاب را می دهد. همینطور کلاس Library برای ما امکان افزودن کتاب جدید را فراهم کرده است.

به ظاهر کار تمام است اما مشکلی وجود دارد.
کلاس سطح بالا (Library) به کلاسی سطح پایین (Book) وابسطه شده است. به این ترتیب اصل وارونگی وابستگی نقض می شود.

علاوه بر این اگر فروشگاه از ما بخواهد برای کاربران علاوه بر کتاب امکان استفاده از کتاب صوتی را نیز فراهم کنیم به وضوح اصل دیگری از SOLID را هم نقض کرده ایم.( اصل باز/بسته )

class AudioBook {
  void seeReviews() {
    // logic audio-book reviews
  }

  void listenSample() {
    // logic listen audio-book-sample
  }
}

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

۲- مثال زیر DIP را رعایت می کند.

برای حل مشکل، یک interface برای کلاس های سطح پایین (کتاب و کتاب صوتی) ایجاد می کنیم. بدین منظور از یک interface به نام Product استفاده می کنیم، که باید هر دو کلاس آن را ایمپلمنت کنند.
برای درک بهتر کد زیر را دنبال کنید:

abstract class Product {
  void seeReviews();
  void getSample();
}

class Book implements Product {
  @override
  void seeReviews() {
    // logic book reviews
  }

  @override
  void getSample() {
    // logic book-sample
  }
}

class AudioBook implements Product {
  @override
  void seeReviews() {
    // logic audio-book reviews
  }

  @override
  void getSample() {
    // logic audio-book-sample
  }
}

همانطور که کد ریفکتور شده کتابخانه را در ادامه خواهید دید، در کلاس Library به جای ارجاع مستقیم به Book و AudioBook از اینترفیس Product استفاده می کنیم. به این صورت امکان افزودن محصولات جدیدی (مثلا مجله و .. ) نیز فراهم می شود و کاربران می توانند آنها را به کتابخانه خود اضافه کنند.

class Library {

    late Product product;

    void addProduct(Product product) {
          // logic add product (can be book or audio-book)
    }
}

کد بالا از اصل جایگزینی Liskov نیز پیروی می کند، چون Product را می توان با هر دو زیرشاخه آن بدون شکستن برنامه جایگزین کرد. همزمان، ما اصل وارونگی وابستگی را نیز پیاده‌سازی کرده‌ایم، زیرا در کد ریفکتور شده ، کلاس‌های سطح بالا به کلاس‌های سطح پایین وابسته نیستند.


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

مقدمه ای بر SOLID

توضیح اصل اول : Single Responsibility Principle

توضیح اصل دوم : Open Closed Principle

توضیح اصل سوم : Liskov Substitution Principle

توضیح اصل چهارم : Interface Segregation Principle

توضیح اصل پنجم : Dependency Inversion Principle