[inversion-of-control] ما هو انقلاب التحكم؟


Answers

يعد انقلاب التحكم هو ما تحصل عليه عند معاودة اتصالك بالبرنامج ، على سبيل المثال ، مثل برنامج واجهة المستخدم الرسومية.

على سبيل المثال ، في قائمة المدرسة القديمة ، قد يكون لديك:

print "enter your name"
read name
print "enter your address"
read address
etc...
store in database

وبالتالي السيطرة على تدفق تفاعل المستخدم.

في برنامج GUI أو somesuch ، بدلا من ذلك نقول

when the user types in field a, store it in NAME
when the user types in field b, store it in ADDRESS
when the user clicks the save button, call StoreInDatabase

حتى الآن يتم عكس التحكم ... بدلاً من الكمبيوتر الذي يقبل إدخال المستخدم بترتيب ثابت ، يتحكم المستخدم في ترتيب إدخال البيانات ، وعندما يتم حفظ البيانات في قاعدة البيانات.

بشكل أساسي ، يقع أي شيء يتضمن حلقة حدث أو عمليات رد اتصال أو ينفذ المشغّلات ضمن هذه الفئة.

Question

يمكن أن يكون انقلاب التحكم (أو IoC) مربكًا جدًا عند اكتشافه لأول مرة.

  1. ما هذا؟
  2. ماذا تحل من مشكلات؟
  3. متى يكون مناسبًا ومتى لا؟



يبدو أن أكثر شيء محيرًا حول "IoC" هو الاسم المختصر والاسم الذي تمثله هو أنه ساحر جدًا لاسم - اسم ضجيج تقريبًا.

هل نحتاج حقًا إلى اسم يمكن من خلاله وصف الاختلاف بين البرمجة الإجرائية والحدثية؟ حسنًا ، إذا احتجنا ، ولكن هل نحتاج إلى اختيار اسم جديد "أكبر من الحياة" يربك أكثر مما يحل؟




افترض أنك كائن. وانت تذهب الى مطعم:

بدون IoC : تسأل عن "apple" ، ويتم تقديمك دائمًا إلى Apple عندما تطلب المزيد.

مع IoC : يمكنك أن تسأل عن "الفاكهة". يمكنك الحصول على ثمار مختلفة في كل مرة يتم تقديمك فيها. على سبيل المثال ، التفاح ، والبرتقال ، أو البطيخ.

لذلك ، من الواضح ، يفضل IoC عندما تحب الأصناف.




I like this explanation: http://joelabrahamsson.com/inversion-of-control-an-introduction-with-examples-in-net/

It start simple and shows code examples as well.

The consumer, X, needs the consumed class, Y, to accomplish something. That's all good and natural, but does X really need to know that it uses Y?

Isn't it enough that X knows that it uses something that has the behavior, the methods, properties etc, of Y without knowing who actually implements the behavior?

By extracting an abstract definition of the behavior used by X in Y, illustrated as I below, and letting the consumer X use an instance of that instead of Y it can continue to do what it does without having to know the specifics about Y.

In the illustration above Y implements I and X uses an instance of I. While it's quite possible that X still uses Y what's interesting is that X doesn't know that. It just knows that it uses something that implements I.

Read article for further info and description of benefits such as:

  • X is not dependent on Y anymore
  • More flexible, implementation can be decided in runtime
  • Isolation of code unit, easier testing

...




سأقوم بتدوين فهمي البسيط لهذين المصطلحين:

For quick understanding just read examples*

Dependency Injection (DI):
ويعني حقن الاعتمادية عمومًا تمرير كائن تعتمد عليه الطريقة كمعلمة إلى طريقة ، بدلاً من أن تقوم الطريقة بإنشاء الكائن التابع .
ما يعنيه في الواقع هو أن الطريقة لا تعتمد بشكل مباشر على تنفيذ معين ؛ يمكن تمرير أي تطبيق يلبي المتطلبات كمعلمة.

مع هذه الأشياء اقول التبعيات لها. والربيع يجعلها متاحة.
هذا يؤدي إلى تطوير التطبيقات المقترنة فضفاضة.

Quick Example:EMPLOYEE OBJECT WHEN CREATED,
              IT WILL AUTOMATICALLY CREATE ADDRESS OBJECT
   (if address is defines as dependency by Employee object)

انعكاس حاوية التحكم (IoC):
هذا هو سمة شائعة من الأطر ، تدير اللجنة الأولمبية الدولية كائنات جافا
- من إصرار إلى تدمير من خلال BeanFactory.
- تسمى مكونات Java التي تم إنشاؤها بواسطة حاوية IoC beans ، وتقوم حاوية IoC بإدارة نطاق bons وأحداث دورة الحياة وأي ميزات AOP تم تكوينها وترميزها.

QUICK EXAMPLE:Inversion of Control is about getting freedom, more flexibility, and less dependency. When you are using a desktop computer, you are slaved (or say, controlled). You have to sit before a screen and look at it. Using keyboard to type and using mouse to navigate. And a bad written software can slave you even more. If you replaced your desktop with a laptop, then you somewhat inverted control. You can easily take it and move around. So now you can control where you are with your computer, instead of computer controlling it QUICK EXAMPLE:Inversion of Control is about getting freedom, more flexibility, and less dependency. When you are using a desktop computer, you are slaved (or say, controlled). You have to sit before a screen and look at it. Using keyboard to type and using mouse to navigate. And a bad written software can slave you even more. If you replaced your desktop with a laptop, then you somewhat inverted control. You can easily take it and move around. So now you can control where you are with your computer, instead of computer controlling it .

من خلال تطبيق Inversion of Control ، يحصل مستعمِل البرنامج / الكائن على المزيد من الضوابط / الخيارات على البرنامج / الكائنات ، بدلاً من التحكم فيه أو الحصول على خيارات أقل.

إن انقلاب التحكم كمبدأ توجيهي يخدم الأغراض التالية:

هناك فصل بين تنفيذ مهمة معينة من التنفيذ.
كل وحدة يمكن أن تركز على ما تم تصميمه ل.
لا تقدم الوحدات أي افتراضات حول ما تفعله الأنظمة الأخرى ولكنها تعتمد على عقودها.
استبدال الوحدات ليس له أي أثر جانبي على الوحدات الأخرى
سأبقي الأمور مجردة هنا ، يمكنك زيارة الروابط التالية للحصول على تفاصيل حول الموضوع.
قراءة جيدة مع المثال

شرح مفصل




يتعلق IoC بمعالجة العلاقة بين رمزك ورمز الطرف الثالث (المكتبة / الإطار):

  • في تطوير s / w العادي ، تكتب الطرق الرئيسية () وطرق "المكتبة". أنت في السيطرة :)
  • في IoC يتحكم "الإطار" main () ويستدعي أساليبك. الإطار هو في السيطرة :(

DI (Dependency Injection) هو حول كيفية تدفق التحكم في التطبيق. يحتوي تطبيق سطح المكتب التقليدي على تدفق التحكم من تطبيقك (طريقة main () لمكالمات طريقة المكتبة الأخرى ، ولكن مع تدفق التحكم في DI يكون معكوسًا ، حيث يعتني إطار العمل بتشغيل تطبيقك ، وتهيئته واستدعاء الأساليب الخاصة بك كلما تطلب الأمر ذلك.

في النهاية تفوز دائما :)




Using IoC you are not new'ing up your objects. Your IoC container will do that and manage the lifetime of them.

It solves the problem of having to manually change every instantiation of one type of object to another.

من المناسب عندما يكون لديك وظيفة قد تتغير في المستقبل أو قد تختلف باختلاف البيئة أو التهيئة المستخدمة في.




IoC is also known as dependency injection (DI). It is a process whereby objects define their dependencies, that is, the other objects they work with, only through constructor arguments, arguments to a factory method, or properties that are set on the object instance after it is constructed or returned from a factory method. The container then injects those dependencies when it creates the bean. This process is fundamentally the inverse, hence the name Inversion of Control (IoC), of the bean itself controlling the instantiation or location of its dependencies by using direct construction of classes, or a mechanism such as the Service Locator pattern

Spring-framework-referance.pfd page 27 (if counting all pdf document pages, it is in page 51)

http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/pdf/spring-framework-reference.pdf




I found a very clear example here which explains how the 'control is inverted'.

Classic code (without Dependency injection)

Here is how a code not using DI will roughly work:

  • Application needs Foo (eg a controller), so:
  • Application creates Foo
  • Application calls Foo
    • Foo needs Bar (eg a service), so:
    • Foo creates Bar
    • Foo calls Bar
      • Bar needs Bim (a service, a repository, …), so:
      • Bar creates Bim
      • Bar does something

Using dependency injection

Here is how a code using DI will roughly work:

  • Application needs Foo, which needs Bar, which needs Bim, so:
  • Application creates Bim
  • Application creates Bar and gives it Bim
  • Application creates Foo and gives it Bar
  • Application calls Foo
    • Foo calls Bar
      • Bar does something

The control of the dependencies is inverted from one being called to the one calling.

What problems does it solve?

Dependency injection makes it easy to swap with the different implementation of the injected classes. While unit testing you can inject a dummy implementation, which makes the testing a lot easier.

Ex: Suppose your application stores the user uploaded file in the Google Drive, with DI your controller code may look like this:

class SomeController
{
    private $storage;

    function __construct(StorageServiceInterface $storage)
    {
        $this->storage = $storage;
    }

    public function myFunction () 
    {
        return $this->storage->getFile($fileName);
    }
}

class GoogleDriveService implements StorageServiceInterface
{
    public function authenticate($user) {}
    public function putFile($file) {}
    public function getFile($file) {}
}

When your requirements change say, instead of GoogleDrive you are asked to use the Dropbox. You only need to write a dropbox implementation for the StorageServiceInterface. You don't have make any changes in the controller as long as Dropbox implementation adheres to the StorageServiceInterface.

While testing you can create the mock for the StorageServiceInterface with the dummy implementation where all the methods return null(or any predefined value as per your testing requirement).

Instead if you had the controller class to construct the storage object with the new keyword like this:

class SomeController
{
    private $storage;

    function __construct()
    {
        $this->storage = new GoogleDriveService();
    }

    public function myFunction () 
    {
        return $this->storage->getFile($fileName);
    }
}

When you want to change with the Dropbox implementation you have to replace all the lines where new GoogleDriveService object is constructed and use the DropboxService. Besides when testing the SomeController class the constructor always expects the GoogleDriveService class and the actual methods of this class are triggered.

When is it appropriate and when not? In my opinion you use DI when you think there are (or there can be) alternative implementations of a class.




قبل استخدام انقلاب التحكم ، يجب أن تكون مدركًا تمامًا لحقيقة أنه يمتلك إيجابياته وسلبياته ويجب أن تعرف سبب استخدامه إذا فعلت ذلك.

الايجابيات:

  • يتم فصل التعليمات البرمجية الخاصة بك بحيث يمكنك بسهولة تبادل تطبيقات واجهة مع تطبيقات بديلة
  • إنه محفز قوي للتشفير ضد واجهات بدلاً من التطبيقات
  • من السهل جدًا كتابة اختبارات الوحدة لرمزك لأنه يعتمد على أي شيء آخر غير الكائنات التي يقبلها في مُنشئه / وسيطه ويمكنك بسهولة تهيئتها بالأشياء الصحيحة في عزلة.

سلبيات:

  • لا تقوم IoC فقط بتعكس تدفق التحكم في البرنامج الخاص بك ، ولكنها أيضاً تقوم بسحبه بشكل كبير. هذا يعني أنه لا يمكنك بعد الآن قراءة التعليمات البرمجية والقفز من مكان إلى آخر لأن الاتصالات التي من الطبيعي أن تكون في التعليمات البرمجية الخاصة بك لم تعد موجودة في التعليمات البرمجية. بدلاً من ذلك في ملفات تكوين XML أو التعليقات التوضيحية وفي رمز حاوية IoC الذي يفسر هذه البيانات التعريفية.
  • هناك فئة جديدة من الأخطاء حيث تحصل على تهيئة XML أو التعليقات التوضيحية بشكل خاطئ ، ويمكنك قضاء الكثير من الوقت في معرفة سبب قيام حاوية IoC بحقن إشارة فارغة إلى أحد كائناتك في ظل ظروف معينة.

أنا شخصياً أرى النقاط القوية في IoC وأحبها حقًا ، لكنني أميل إلى تجنب IoC كلما أمكن ذلك ، لأنه يحول برنامجك إلى مجموعة من الطبقات التي لم تعد تشكل برنامجًا "حقيقيًا" ، بل مجرد شيء يحتاج إلى وضعه معًا تهيئة XML أو بيانات تعريف التعليقات التوضيحية وسينخفض ​​(وينهار) بدونها.




انعكاس الضوابط هو حول فصل المخاوف.

بدون IoC : لديك جهاز كمبيوتر محمول وتقوم بكسر الشاشة عن طريق الخطأ. والرتق ، تجد نفس شاشة الكمبيوتر المحمول طراز هو في أي مكان في السوق. إذن أنت عالق

مع IoC : لديك جهاز كمبيوتر مكتبي وتكسر الشاشة عن طريق الخطأ. ستجد أنه بإمكانك الاستيلاء على أي شاشة سطح مكتب تقريبًا من السوق ، وتعمل بشكل جيد مع سطح المكتب.

يعمل سطح المكتب الخاص بك بنجاح على تطبيق IoC في هذه الحالة. إنه يقبل نوعًا متنوعًا من الشاشات ، بينما لا يعمل الكمبيوتر المحمول ، يحتاج إلى شاشة محددة ليتم إصلاحها.




دعونا نقول أننا نجعل بعض الاجتماع في بعض الفنادق.

كثير من الناس ، والكثير من المرايا من الماء ، وكأس بلاستيكية كثيرة.

عندما يريد شخص ما الشرب ، تملأ الكأس وتشرب وترمي الكأس على الأرض.

بعد ساعة أو شيء لدينا أرضية مغطاة بأكواب بلاستيكية وماء.

دعونا عكس السيطرة.

نفس الاجتماع في نفس المكان ، ولكن بدلا من الكؤوس البلاستيكية لدينا نادل مع كوب واحد من الزجاج (سينجلتون)

وهي توفر كل الوقت للضيوف الشرب.

عندما يريد شخص ما أن يشرب ، تحصل من زجاج النادل ، ويشرب ، ويعيدها إلى النادل.

ترك جانبا مسألة النظافة ، آخر شكل من أشكال مراقبة عملية الشرب هو أكثر فعالية واقتصادية.

وهذا هو بالضبط ما يفعله الربيع (حاوية IoC أخرى ، على سبيل المثال: Guice). بدلاً من السماح للتطبيق بإنشاء ما يحتاجه باستخدام كلمة رئيسية جديدة (مع كوب بلاستيكي) ، تقدم حاوية Spring IoC كل الوقت لتطبيق نفس المثيل (singleton) للكائن المطلوب (كوب من الماء).

فكر في نفسك كمنظم لهذا الاجتماع. أنت في حاجة إلى طريقة لرسالة إلى إدارة الفندق ذلك

يحتاج أعضاء الاجتماع إلى كوب من الماء ولكن ليس قطعة من الكعكة.

مثال:-

public class MeetingMember {

    private GlassOfWater glassOfWater;

    ...

    public void setGlassOfWater(GlassOfWater glassOfWater){
        this.glassOfWater = glassOfWater;
    }
    //your glassOfWater object initialized and ready to use...
    //spring IoC  called setGlassOfWater method itself in order to
    //offer to meetingMember glassOfWater instance

}

روابط مفيدة:-




Creating an object within class is called tight coupling, Spring removes this dependency by following a design pattern(DI/IOC). In which object of class in passed in constructor rather than creating in class. More over we give super class reference variable in constructor to define more general structure.




لكن أعتقد أنه عليك أن تكون حذرا للغاية معها. إذا كنت ستفرط في استخدام هذا النمط ، فستصنع تصميمًا معقدًا للغاية وحتى رمزًا أكثر تعقيدًا.

مثل في هذا المثال مع TextEditor: إذا كان لديك واحد فقط SpellChecker ربما ليس من الضروري استخدام IoC بالفعل؟ ما لم تكن بحاجة إلى كتابة اختبارات الوحدة أو شيء من هذا ...

على أي حال: كن معقولا. نمط التصميم هو ممارسات جيدة ولكن ليس الكتاب المقدس يجب أن يتم التبشير به. لا تلتصق بها في كل مكان.




البرمجة تحدث

IoC بعبارات سهلة: هو استخدام الواجهة كطريقة لشيء معين (مثل حقل أو معلمة) كحرف بدل يمكن استخدامه من قبل بعض الفئات. يسمح إعادة إمكانية استخدام الرمز.

على سبيل المثال ، لنفترض أن لدينا فئتين: Dog و Cat . كلاهما يتقاسم نفس الصفات / الدول: العمر والحجم والوزن. لذا بدلاً من إنشاء فئة من الخدمة تسمى DogService و CatService ، يمكنني إنشاء واحد يسمى AnimalService يسمح باستخدام Dog و Cat فقط إذا استخدموا الواجهة IAnimal .

ومع ذلك ، بشكل براغماتي ، فقد بعض إلى الوراء.

أ) لا يعرف معظم المطورين كيفية استخدامه . على سبيل المثال ، يمكنني إنشاء فئة تسمى " العميل" ويمكنني إنشاء تلقائياً (باستخدام أدوات IDE) واجهة تسمى ICustomer . لذلك ، ليس من النادر العثور على مجلد مليء بالفصول والواجهات ، بغض النظر عما إذا كان سيتم إعادة استخدام الواجهات أم لا. انها تسمى BLOATED. يمكن لبعض الناس أن يجادلوا أنه "قد يكون في المستقبل يمكننا استخدامه". : - |

ب) لديها بعض القيود. على سبيل المثال ، دعنا نتحدث عن حالة Dog and Cat وأريد إضافة خدمة جديدة (وظيفة) فقط للكلاب. دعنا نقول أنني أريد حساب عدد الأيام التي trainDays() لتدريب كلب ( trainDays() ) ، لأنه غير مجدية ، لا يمكن تدريب القطط (أنا أمزح).

ب) إذا قمت بإضافة trainDays() إلى خدمة AnimalService ، فإنها تعمل أيضًا مع القطط وهي غير صالحة على الإطلاق.

ب) يمكنني إضافة شرط في trainDays() حيث يتم تقييم الفئة التي يتم استخدامها. لكنه سوف يكسر تماما IoC.

ب. 3) يمكنني إنشاء فئة جديدة من الخدمات تسمى DogService للوظائف الجديدة فقط. ولكن ، سيزيد من المحافظة على الشفرة لأننا سنحصل على فئتين من الخدمة (مع وظائف مماثلة) لكلب وأنها سيئة.




Related