ورود ثبت نام

ورود به حساب کاربری

نام کاربری *
رمز ورود *

ایجاد حساب کاربری

گزینه های * دار الزامی می باشند.
نام *
نام کاربری *
رمز ورود *
تائیدیه رمز ورود *
نشانی پست الکترونیک *
تائیدیه پست الکترونیک *

وارونگی کنترل یک اصل طراحی شی گرایی است که در آن کنترل ماژولهای نرم افزار در مقایسه با برنامه نویسی رویه ای سنتی بالعکس می شود. به عنوان مثال فرض کنید شما می خواهید در محل کارخود کاری را انجام دهید و برای انجام کار باید با  ماشین رانندگی نیز انجام دهید. باکمک IOC شما از یک راننده استفاده می کنید تا برای شما کار رانندگی را انجام دهد و شما روی کار خود تمرکز می نمایید. این اصل برای افزایش ماژولار بودن برنامه (پیمانه ای بودن) و انعطاف پذیری آن و از بین بردن به هم پیوستگی شدید (tightly coupled) و رسیدن به کمترین میزان وابستگی (loosely coupled) می باشد.

اگر ما فرض کنیم که طبق شکل زیر کلاسی داریم که قرار است از دو سرویس A و B استفاده کند در نتیجه کلاس ما دارایوابستگی شدید به دو سرویس است و مشکلات زیر به وجود می آید:

وارونگی کنترل

  • با تغییر و بروزرسانی در سرویسها شما مجبور هستید که کلاس خود را نیز تغییر دهید
  • یک نمونه پیاده سازی شده و در دسترس که قابل تست باشد تنها در زمان کامپایل برنامه در دسترس خواهد بود.
  • تست کلاس با توجه به وابستگی به سرویسها بسیار مشکل خواهد بود.
  • کدهای مربوط به ایجاد و مقداردهی اولیه سرویس ها در کلاس قرار دارد که دراین صورت اگر به هر دلیل خطایی در ایجاد آنها رخ دهد کلاس نمی تواند به کار خود ادامه دهد.

اجازه دهید تا در اینجا نحوه تغییر جریان کنترل را به شیوه های مختلف توسط IOC را بهتر شرحدهیم:

کنترل روی جریان یک برنامه

در یک برنامه کنسولی سی شارپ اجرا از تابع main() آغاز می شود و کنترل جریان برنامه با ترتیب اجرای دستورات توسط آن صورت می گیرد. به مثال زیر در این رابطه نگاه کنید:

namespace FlowControlDemo
{
    class Program
    {
        static void Main(string[] args)
        {
           bool continueExecution = true;
            do
            {
                Console.Write("Enter First Name:");
                var firstName = Console.ReadLine();

                Console.Write("Enter Last Name:");
                var lastName = Console.ReadLine();

                Console.Write("Do you want to save it? Y/N: ");

                var wantToSave = Console.ReadLine();

                if (wantToSave.ToUpper() == "Y")
                    SaveToDB(firstName, lastName);

                Console.Write("Do you want to exit? Y/N: ");

                var wantToExit = Console.ReadLine();

                if (wantToExit.ToUpper() == "Y")
                    continueExecution = false;

            }while (continueExecution);
         
        }

        private static void SaveToDB(string firstName, string lastName)
        {
            //save firstName and lastName to the database here..
        }
    }
}

در این شبه کد با ورود نام و نام خانوادگی توسط کاربر، اطلاعات توسط تابع main() ذخیره شده و در صورت تمایل کاربر برنامه پایان می یابد. این یک نمونه ساده از پیاده سازی IOC روی جریان برنامه بود.

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

ابتدا اجازه دهید که معنی وابستگی را بهتر شرح دهیم. به مثال زیر توجه کنید:

public class A
{
    B b;

    public A()
    {
        b = new B();
    }

    public void Task1() {
        // do something here..
        b.SomeMethod();
        // do something here..
    }

}

public class B {

    public void SomeMethod() { 
        //doing something..
    }
}

در مثال بالا کلاس A تابع b.SomeMethod() از کلاس B را برای تکمیل وظیفه خود صدا می زند. کلاس A بدون کلاس B قادر به تکمیل کار خود نمی باشد بنابراین ما می توانیم بگوییم کلاس A به کلاس B وابسته است و کلاس B ازوابستگی های کلاس A می باشد.

در طراحی شی گرا کلاسها می توانند با همدیگر تعامل داشته باشند و مدیریت چرخه زندکی یکدیگر را بر عهده بگیرند مانند بالا که مدیریت چرخه زندگی کلاس B به دست کلاس A می باشد.

IOC می تواند کنترل ایجاد کلاس وابسته را وارون نماید و کنترل لیجاد را در مثال بالا از کلاس A به کلاس دیگر بدهد.

public class A
{
    B b;

    public A()
    {
        b = Factory.GetObjectOfB ();
    }

    public void Task1() {
        // do something here..
        b.SomeMethod();
        // do something here..
    }
}

public class Factory
{
    public static B GetObjectOfB() 
    {
        return new B();
    }
}

همانطور که در شبه کد بالا دیده می شود، کلاس A از کلاس Factory برای ایجاد یک نمونه از کلاس B استفاده می نماید. بنابراین، ما کنترل ایجاد کلاس وابسته را از کلاس A به کلاس Factory داده ایم. برای درک بهتر این موضوع اجازه دهید یک مثال دیگر بزنیم. در طراحی شی گرایی کلاسها باید به صورت loosely coupled طراحی شوند و این بدان معناست که تغییرات روی یک کلاس نباید باعث تغییر در دیکر کلاسها شود. به شکل زیر توجه کنید:

وارونگی کنترل

شکل بالا الگوی طراحی لایه ای نرم افزار را نشان می دهد. در این الگو رابط کاربری از لایه سرویس برای واکشی و ذخیره اطلاعات استفاده می کند. لایه سرویس نیز خود از لایه منطق تجاری برای اعمال نقش ها و قوانین موجود در آن روی داده کمک می برد. و در نهایت لایه منطق تجاری نیز از لایه DataAccess برای ذخیره و بازیابی اطلاعات در پایگاه داده استفاده می نماید. در اینجا ما روی دو لایه BusinessLogic و DataAccess برای درک IOC تمرکز می نماییم.

در زیر شبه کد مربوط به این دو لایه (کلاس) برای موجودیت مشتری آورده شده است:

public class CustomerBusinessLogic
{
    DataAccess _dataAccess;

    public CustomerBusinessLogic()
    {
        _dataAccess = new DataAccess();
    }

    public string GetCustomerName(int id)
    {
        return _dataAccess.GetCustomerName(id);
    }
}

public class DataAccess
{
    public DataAccess()
    {
    }

    public string GetCustomerName(int id) {
        return "Dummy Customer Name"; // get it from DB in real app
    }
}

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

در این مثال دو کلاس DataAccess و CustomerBusinessLogic از نوع وابسته (tightly coupled) هستند زیرا کلاس CustomerBusinessLogic دارای یک نمونه از کلاس DataAccess در خود است که کنترل چرخه زندگی آنرا نیز در دست داردو مشکلات زیر پیش می آید:

  • تغییرات روی کلاس DataAccess باعث تغییر در کلاس CustomerBusinessLogic می شود. برای مثال اگر ما متد جدیدی به DataAccess اضافه کنیم و یا یک مت آن را تغییر نام دهیم و یا حذف نماییم باید کلاس CustomerBusinessLogic را نیز تغییر دهیم.
  • در نظر بگیرید، در آینده نیاز باشد اطلاعات مشتری از پایگا داده و یا وب سرویس متفاوتی گرفته شود. بنابراین، ما نیاز به تغییر کلاس CustomerBusinessLogic خواهیم داشت.
  • فرض کنید نام کلاس DataAccess تغییر نمود. در این حالت باید هر جایی که یک نمونه از آن را در برنامه و کلاس CustomerBusinessLogic ساخته اید را تغییر دهید.
  • امکان تست مستقل کلاس CustomerBusinessLogic با توجه به استفاده مستقیم و ایجاد کلاس DataAccess در آن وجود ندارد.

بنابراین راه کار رفع نقایص بالا پیاده سازی اصل IOC در برنامه می باشد.

وارونگی کنترل

این اصل برای پیاده سازی دارای تکنیک های مختلف است که در زیر لیست آنها آمده است:

  • استفاده از یک service locator pattern
  • استفاده از dependency injection (برای آشنایی بیشتر با این مورد به تزریق وابستگی  بروید)
    • Constructor injection
    • Parameter injection
    • Setter injection
    • Interface injection
  • استفاده از یک Abstract Factory design pattern
  • استفاده از یک Factory design pattern
  • استفاده از template method design pattern
  • استفاده از strategy design pattern

به طور مثال برای پیاده سازی الگوی IOC در کد بالا از روش Factory Pattern استفاده می کنیم و در گام اول یک کلاس Factory که یک نمونه از کلاس

public class DataAccessFactory
{
    public static DataAccess GetDataAccessObj() 
    {
        return new DataAccess();
    }
}

و در ادامه از این کلاس در کلاس CustomerBusinessLogic استفاده می نماییم.

    public CustomerBusinessLogic()
    {
    }

    public string GetCustomerName(int id)
    {
        DataAccess _dataAccess =  DataAccessFactory.GetDataAccessObj();

        return _dataAccess.GetCustomerName(id);
    }
}

همانطور که می بینید کلاس CustomerBusinessLogic از متد DataAccessFactory.GetDataAccessObj() برای داشتن یک نمونه از کلاس DataAccess به جای استفاده از کلمه کلیدی new برای ایجاد آن استفاده می کند. بنابراین ما کنترل ایجاد کلاس را از CustomerBusinessLogic به کلاس DataAccessFactory اعطا نمودیم

نوشتن دیدگاه


تصویر امنیتی
تصویر امنیتی جدید