سؤال

أنا أستخدم قلعة ويندسور في مشروع للحيوانات الأليفة أعمل عليه.بدأت ألاحظ أنني بحاجة إلى استدعاء حاوية IoC في أماكن مختلفة في الكود الخاص بي لإنشاء كائنات جديدة.هذا الاعتماد على الحاوية يجعل الحفاظ على الكود الخاص بي أكثر صعوبة.

هناك حلان استخدمتهما لحل هذه المشكلة

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

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

كلا الحلين يعملان نوعًا ما ولكن كلاهما لهما عيوبهما.لذلك أشعر بالفضول لمعرفة ما إذا كان هناك أشخاص آخرون واجهوا نفس المشكلة ووجدوا حلولاً أفضل.


يحررالمشكلة ليست في الكائن A الذي يعتمد على الكائن B.عادةً ما أستخدم هنا حقن المنشئ وكل شيء يعمل.في بعض الأحيان يكون لدي كائنات من النوع A تحتاج إلى إنشاء عدد متغير من الكائنات الأخرى من النوع B خلال فترة حياتها.لست متأكدا من كيفية القيام بذلك.

@ بلير كونراد:مشاكل الصيانة ليست خطيرة حتى الآن.كان لدي بعض الفئات التي تعتمد على كائن الحاوية الذي يستدعي الحاوية.الحل<>.ولا أريد أن يعتمد الكود الخاص بي على ما أعتقد أنه البنية التحتية.ما زلت أحاول تجربة الأشياء، لذا لاحظت أنني اضطررت إلى تغيير الكثير من التعليمات البرمجية عند التبديل من ninject إلى castel لهذا المشروع.

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

هل كانت مفيدة؟

المحلول

الميزة الرئيسية لحقن التبعية، على الأقل في تطبيقاتي، هي القدرة على كتابة تعليمات برمجية لا تعتمد على السياق.ومن هذا المنظور، يبدو الحل الثاني وكأنه يفسد بالفعل الفائدة التي يمكن أن تقدمها لك شركة DI.إذا كشف "كائن الإله" عن واجهات مختلفة لكل فئة تشير إليه، فقد لا يكون ذلك شريرًا للغاية.ولكن إذا ذهبت إلى هذا الحد، فلا أرى سببًا لعدم قطع كل الطريق إلى الطوق.

مثال:يحتوي كائن God الخاص بك على طريقة getFoo() وطريقة getBar().الكائن A يحتاج إلى Foo، والكائن B يحتاج إلى شريط.إذا كان "أ" يحتاج إلى "فو" واحد فقط، فيجب حقن "فو" مباشرة في "أ" ويجب ألا يكون "أ" على دراية بالله على الإطلاق.ولكن إذا احتاج "أ" إلى الاستمرار في إنشاء Foos، فإن إعطاء "A" إشارة إلى الله أمر لا مفر منه إلى حد كبير.لكن يمكنك أن تحمي نفسك من الضرر الناتج عن تجاوز الله عن طريق تضييق نوع الإشارة إلى الله.إذا جعلت الله ينفذ FooFactory وأعطيت A إشارة إلى FooFactory الذي نفذه الله، فلا يزال بإمكانك كتابة الكود في A بطريقة محايدة للسياق.يؤدي ذلك إلى تحسين فرص إعادة استخدام التعليمات البرمجية، ويزيد من ثقتك في أن التغيير إلى الله لن يسبب آثارًا جانبية غير متوقعة.على سبيل المثال، يمكنك التأكد عند إزالة getBar() من الله أن الفئة A لن تنكسر.

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

نصائح أخرى

من فضلك، لا تستخدم أبدًا فئات ثابتة مثل IoC.Container.Resolve أو ContainerFactory.GetContainer!

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

عادةً ما يحتوي أي مكون أو خدمة على نقطة حقن واحدة فقط - وهي المُنشئ (مع خصائص اختيارية).وبشكل عام، لا ينبغي للمكونات أو فئات الخدمة الخاصة بك أن تعرف أبدًا بوجود شيء مثل الحاوية.

إذا كانت مكوناتك تحتاج حقًا إلى دقة ديناميكية بالداخل (على سبيل المثال.حل سياسة معالجة الاستثناءات أو سير العمل، بناءً على الاسم)، فإنني أوصي بمراعاة ذلك إقراض صلاحيات IoC عبر مقدمي خدمات محددين للغاية

أوصي بمراجعة سلسلة Nick Blumhardt المصغرة حول هذا الموضوع.

http://blogs.msdn.com/nblumhardt/archive/2008/12/27/container-managed-application-design-prelude-where-does-the-container-belong.aspx

على الرغم من أنني أقدر وضوح "المصانع المصممة لهذا الغرض" وحتى استخدامها بنفسي، فإن هذا يبدو وكأنه رائحة كود في تصميماتي الخاصة لأن الواجهة العامة ("i الصغيرة") تتغير باستمرار مع مصنع جديد و/أو طريقة GetX جديدة لكل تنفيذ.بعد قراءة جيريمي ميلر حان الوقت لانفراج حاوية IoC, أظن أن الأدوية الجنيسة وحقن الحاوية نفسها هي الطريقة الصحيحة.

سأقوم بتغليف Ninject أو StructureMap أو Windsor في نوع ما من واجهة IServiceLocator مثل تلك المقترحة في مقالة جيريمي.ثم لديك مصنع حاويات يقوم ببساطة بإرجاع IServiceLocator في أي مكان في التعليمات البرمجية الخاصة بك، حتى في الحلقات كما اقترحت في الأصل.

IServiceLocator container = ContainerFactory.GetContainer(); 
while( keepLooping )
{
    IExample example = container.GetInstance<IExample>();
    keepLooping = example.DoWork();
}

يمكن لمصنع الحاويات الخاص بك دائمًا إرجاع نفس المثيل، ويمكنك تبديل أطر عمل IoC، أيًا كان.

كمتابعة ل @flipdoubt

إذا انتهى بك الأمر إلى استخدام نمط نوع محدد موقع الخدمة، فقد ترغب في التحقق من ذلك http://www.codeplex.com/CommonServiceLocator.يحتوي على بعض الارتباطات المتاحة للعديد من أطر عمل IoC الشائعة (windsor، Structuremap) والتي قد تكون مفيدة.

حظ سعيد.

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

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

إن CommonServiceLocator ليس مخصصًا لهذا الغرض، على الرغم من أنه قد يميل المرء إلى استخدامه.الغرض الرئيسي من CommonServiceLocator هو التطبيقات/الأطر التي تريد أن تكون متوافقة مع حاوية IoC.ومع ذلك، يجب على التطبيقات التي تستخدم الاتصال بمحدد المواقع مرة واحدة فقط على النحو الأمثل لإنشاء تسلسل هرمي للمكونات وتبعياتها.لا ينبغي أبدا أن يتم استدعاؤه مباشرة مرة أخرى.لو كان لدينا طريقة ما لفرض ذلك لفعلنا ذلك.في بريزم (http://www.microsoft.com/compositewpf) قدمنا ​​IContainerFacade لبناء الوحدات.هذا هو محدد مواقع الخدمة على الرغم من أنه ذو مستوى منخفض.في وقت لاحق، ربما كان علينا إنشاء ModuleFactory أو شيء من هذا القبيل واستخدام IContianerFacade للحصول عليه، ثم استخدام وحدات الحل هذه مقابل الانتقال إلى الواجهة مباشرة.الإدراك المتأخر هو 20/20.إنه مستوى منخفض بدرجة كافية على الرغم من أنه لا يؤثر حقًا على الأشياء.

في CSL، تصارعنا مع التسمية لأنها قد تؤدي إلى الارتباك.في النهاية قررنا استخدام CSL لأن الواجهة من الناحية الفنية لا تتيح لك القيام بـ DI.

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

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top