IOC دقیقا چیه !؟

پرسیده شده
فعالیت 1075 روز پیش
دیده شده 652 بار
0

سلام استاد 

وقتتون بخیر

ببخشید یه سوالی که داشتم اینه که من توضیحات تون رو بابت IOC توی ویدیو گوش دادم ولی از اونجایی که برام واضح نبود یه چندتا مقاله خوندم و مشکلی که در درکش همچنان دارم اینه که خود IOC که فرمودید یه سرویسی هست که ارائه شده که مواقعی که میخواییم objectی از یک class رو new کنیم میتونیم ازش استفاده کنیم، به چه صورتی وجود داره و اگر بخواییم ازش استفاده کنیم، این نحوه استفاده ازش به چه صورته؟ و چون دیدم در اکثر مقاله هایی که دیدم، با عنوان laravel ioc  نوشته شده، این سرویس فقط داخل لاراول هستش یا نه !؟

 

چون مثلا در این مقاله ، IOC یک کلاسی هستش که از متد استاتیکش استفاده کرده و مثال زده و جاهای دیگه هم درک واضحی از این مفهوم رو توضیح ندادن.

ممنون میشم بیشتر راهنمایی بفرمائید

فایل پیوست

امیر ابوئی
امیر ابوئی

4 خرداد 00

3
حذف شده

سلام و احترام

اول بیایید یه چندتا مشکل رو بررسی کنیم و ببینیم که اصلا چرا IOC اومده

فرض کنید شما یه سرویس کش توی پروژه تون و دارید ازش استفاده میکنید، حالا وسط پروژه متوجه میشید که این سرویس کشی که استفاده کردید زیاد مناسب نیست و میخواهید عوضش کنید یا اینکه فرض کنید دارید دارید از یه دیتابیس استفاده میکنید و بنا بر نیازی میخواهید سری به یه دیتابیس دیگه جا به جا بشید. فرض میکنید اگه این کارها رو توی پروژتون انجام بدید چی میشه؟ 

قطعا شاید از شما کلی زمان ببره تا این جا به جایی رو انجام بدید یا اینکه سرویس کشتون رو عوض کنید چون توی همه جای پروژتون استفاده کردید و ریشه کرده داخل تمامی کدهاتون

 

راه حل IOC بود که اصل dependency inversion و dependency injection داخلش به خوبی رعایت میشه، به این شکل که شما برای مثال میایید یک قرارداد کلی برای مثال همین دیتابیس میزارید و میگید که همه کلاس های دیتابیس های من باید متد های delete - update  - select - insert رو داشته باشن، قطعا شما اینجا یه سری قرار داد دارید و یک سری کلاس هایی که این قرار داد هارو پیروی کردند، این interface شما:

<?php




use App\Repository\Contracts\RepositoryInterface;

interface PaymentRepositoryInterface
{

	public function delete();
}

و یه کلاس دارید که این متدهای رو به عنوان قرار داد پذیرفته و پیاده سازیشون کرده، برای مثال کلاس mysql

<?php





use App\Models\Payment;

use App\Repository\Contracts\Payment\PaymentRepositoryInterface;

class MysqlPaymentRepository implements PaymentRepositoryInterface
{
    public function delete()
    {
    	// some code
    }
    

}

و حالا برای مثال ما دوست داریم یه کلاس هم داشته باشیم که با mongodb کار کنه پس

 

<?php





use App\Models\Payment;

use App\Repository\Contracts\Payment\PaymentRepositoryInterface;

class MongoPaymentRepository implements PaymentRepositoryInterface
{
    public function delete()
    {
    	// some code
    }
    

}

حالا ما تصمیم میگیریم که بیاییم به جای mysql از mongodb استفاده کنیم، چه اتفاقی میوفته؟ ما از mysql توی بخش های مختلف new گرفتیم همین باعث شده اصلا dependecy inversion نقص بشه چون وابستگی از کلاس بچه به پدر تعیین شده، ینی اینکه کلاس بچه داره میگه که از پدر چی میخواد، این باید بر عکس باشه، اینجاست که IOC میاد کمکمون

حالا باید چی کار کنیم؟

ما باید جایی باشه که بگیم من وقتی قرارداد PaymentRepositoryInterface  رو خواستم تو به من برای مثال mysql رو بده MysqlPaymentRepository یا طبق نیازم بهم MongoPaymentRepository رو بده. پس توی این بخش داریم یه جورایی این اصل رعایت میکنیم چون پدره  که میگه من میتونیم این موارد رو بهت بدم

 

توی لاراول به این شکله که ما توی provider ها میایم این بخش رو هندل میکنیم، برای مثال

 

<?php


class RepositoryServiceProvider extends ServiceProvider
{
    /**
     * Register services.
     *
     * @return void
     */
    public function register()
    {
        //
    }

    /**
     * Bootstrap services.
     *
     * @return void
     */
    public function boot()
    {
        $this->app->bind(PaymentRepositoryInterface::class, MysqlPaymentRepository::class);
     
    }
}

 

مثلا داخل متد boot گفتیم که اگه interfaceه PaymentRepositoryInterface صدا زده شد کلاس MysqlPaymentRepository رو بهم بده حالا بعدا اگه تصمیم گرفتیم از Mongo استفاده کنیم خیلی راحت به جای کلاس mysql کلاس mongo صدا میزنیم

کاری که لاراول در پشت صحنه میکنه اینکه میره این کلاس ها رو یه شئ ازش میسازه میزاره داخل متد construct هر کلاسی که ازش استفاده کردید، اما خب در کل شما بدون لاراول هم میتونید یه همچین چیزی رو داشته باشید و باید dependency ها از طریق متد construct تزریق کنید تا خیلی راحت بشه اگه خواستیم آبجکت از کلاس های دیگه به اون construct  پاس بدیم

IOC هم توی شی گرایی مطرحه و فقط برای لاراول نیست

 

فایل پیوست

امیر صالحی

توسط

امیر صالحی

4 خرداد 00

1
حذف شده

سلام

بذار یه توضیح مفهومی بدم

یکی از مشکلات اساسی در توسعه نرم افزار مخصوصا وقتیکه module  های نرم افزار بزرگ میشن , بحث وابستگی module به هم هستش

چرا؟

فرض کنید متدی در یکی از کلاس هاس ماژول  A , داره از متد  یکی از کلاس های ماژول B استفاده میکنه .طبق خواسته صاحب محصول برای پیاده سازی قابلیت جدید  باید یک تغییری در اون متد صورت میگیره

اتفاقی که می افتده خروجی متدی که در ماژول B هستش تغییر میکنه و ماژول A  دچار ارور runtime  (منظور از runtime   وقتی هیستش که برنامه به روی سرور و مردم ازش استفاده کنن و اون موقعه ارور بده و شما مجبور باشید بعد از کلی کدنوشتن و اضافه کردم قابلیت های جدید به برنامه , برنامه debug کنید) میشه و یا ارورهای دیگه میشه

به این میگن وابستگی که خیلی بده مخصوصا وقتیکه پروژه بزرگه و چندین برنامه نویس دارن رو پروژه کار میکن

بدترین موقع هم وقتیکه که ماژول ما خارجی یا سطح پایین باشه.یعنی در پوشه vendor باشه و یک پکیچ خارجی باشه .مشکلاتش این میشه که وقتیکه پکیچ بطور کامل منسوخ بشه  یا ما از متدی استفاده کرده باشیم که در نسخه جدید حذف یا  منسوخ یا خروجی که ما ازش انتظار داریم تغییر بکنه ما دچار ارور میشیم یا اصلا دیگه اون پکیج جواب کار ما رو نده و از پکیج دیگه ای استفاده کنیم حالا فرض کن در ۳۰ جای برنامه ما از اون متد استفاده کرده باشیم

این یعنی یه فاجعه

ما باید همیشه اصلا low coupling high cohesion  که به کاهش درهم تنیگدیگی بین ماژول ها و افزایش انسجام داخلی هر ماژول رعایت کنیم.اما از طرفی هم نمیتونیم ماژول ها رو بصورت ۱۰۰% مستقل کنیم

در اینجا باید چیکار کنیم؟

در اینجا ارتباط بین ماژول باید بوسلیه  کلاس ها abstract و interface ها باشه

نباید ماژول بصورت مستقیم از هم دیگه استفاده کنن

وقتیکه از کلاس ها abstract و interface استفاده میکنیم مطئن هستیم خروجی یکسان هستش و اگر نباشه برنامه قبل از اجرا دچار ارور شده و دیگه درحالت runtime  ارور نمیده 

 در اینجا اصل پنجم SOILD با استفاده از همین موضوع abstract و interface ,بحث dependency inversion  ارئه میکنه

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

ما یک کلاس abstract و یک کلاس concrete  داریم

کلاس abstract کلاسی که  متد abstract داره

اما کلاس concrete  کلاسی که  متد abstract نداره و از کلاس  abstract ارث بری میکه

مثلا کلاس AbstractMysqlDBRepository  یک کلاس abstract هستش

و کلاس های EloquentDBRepository و DoctrineDBRepository هم کلاس های concrete   هستن و از کلاس AbstractMysqlDBRepository   ارث میرن و   تمامی متد های داخلی AbstractMysqlDBRepository   داخلش هستن

خوب ما یه جایی به نام app container  داریم.در app container ما تعریف میکنیم هر جا ما نمونه از AbstractMysqlDBRepository    خواستیم به ما یک شی از AbstractMysqlDBRepository    بده

یا DoctrineDBRepository یا یک پکیج که در آینده میتونه اضافه بشه

در این حالت هر جا ما شی از AbstractMysqlDBRepository     بخوایم میدونم که اون متد ما داخلش هست خروجی و ورودی اون متد تغییر نمیکنه اگرهم بکنه در تو حالت runtime دیگه ارور نداریم قبل از runtime هستش که ما میتونیم برطرف کنیم

به این میگن IOC مختصر inversion of control  به معنی وارونگی کنترل  . کنترل چی ؟ کنترل وابستگی

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

کلا تنها راه کتنرل وابستگی استفاده از abstract و interface ها هستش

امیدوارم تونسته باشم  توضیح خوبی داده باشم  چون برای خودم این موضوع خیلی یه زمان مبهم بود

فایل پیوست

محسن محمدخانی

توسط

محسن محمدخانی

5 خرداد 00