الأحد، 1 مارس 2020

برنامج التطبيق

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

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

الآن إذا كنت أستخدم هذه الفئة لنفسي فقط ، فهذا كل شيء على ما يرام. ولكن ماذا يحدث عندما يغمر أصدقائي الرغبة في هذه الوظيفة الرائعة ويرغبون في الحصول على نسخة من برنامجي؟ إذا قاموا أيضًا بتخزين قوائم الأفلام الخاصة بهم في ملف نصي محدد بنقطتين يسمى "movies1.txt" ، فكل شيء رائع. إذا كان لديهم اسم مختلف لملف الأفلام الخاص بهم ، فمن السهل وضع اسم الملف في ملف الخصائص. ولكن ماذا لو كان لديهم شكل مختلف تمامًا لتخزين قوائم الأفلام الخاصة بهم: قاعدة بيانات SQL ، أو ملف XML ، أو خدمة ويب ، أو مجرد تنسيق آخر للملف النصي؟ في هذه الحالة ، نحتاج إلى فصل مختلف للحصول على تلك البيانات. الآن نظرًا لأنني قمت بتعريف واجهة MovieFinder ، فلن يغير هذا طريقة moviesDirectedBy الخاصة بي. لكن ما زلت بحاجة إلى الحصول على طريقة لتطبيق مثيل الباحث الصحيح في مكانه.

يوضح الشكل 1 التبعيات لهذا الموقف. تعتمد فئة MovieLister على كل من واجهة MovieFinder وعلى التنفيذ. نحن نفضل ذلك إذا كانت تعتمد فقط على الواجهة ، ولكن بعد ذلك كيف يمكننا إنشاء مثيل للعمل؟
في كتابي P of EAA ، وصفنا هذا الموقف بأنه مكون إضافي. فئة تنفيذ الباحث غير مرتبطة بالبرنامج في وقت الترجمة ، حيث أنني لا أعرف ما الذي يستخدمه أصدقائي. بدلاً من ذلك ، نريد أن يعمل سيدي في أي تنفيذ ، ولكي يتم توصيل هذا التطبيق في وقت لاحق ، من يدي. المشكلة هي كيف يمكنني إنشاء هذا الرابط بحيث يجهل الفصل الدراسي الخاص بي فئة التنفيذ ، ولكن لا يزال بإمكانه التحدث إلى مثيل للقيام بعمله.

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

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

قلب السيطرة

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

والسؤال هو: "أي جانب من جوانب السيطرة هم قلب؟" عندما واجهت الانقلاب لأول مرة على التحكم ، كان ذلك في التحكم الرئيسي لواجهة المستخدم. تم التحكم في واجهات المستخدم المبكرة بواسطة برنامج التطبيق. سيكون لديك سلسلة من الأوامر مثل "أدخل اسم" ، "أدخل عنوان" ؛ من شأن برنامجك أن يدفع المطالبات ويلتقي استجابة لكل منها. باستخدام واجهة المستخدم الرسومية (أو حتى القائمة على الشاشة) ، فإن إطار عمل واجهة المستخدم يحتوي على هذه الحلقة الرئيسية ، وبدلاً من ذلك ، قدم البرنامج معالجات الأحداث للحقول المختلفة على الشاشة. تم قلب التحكم الرئيسي للبرنامج ، وانتقل بعيدًا عنك إلى الإطار.

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

برنامج تصميم

في مجتمع Java ، كانت هناك اندفاع في حاويات خفيفة الوزن تساعد على تجميع المكونات من مشاريع مختلفة في تطبيق متماسك. تشكل هذه الحاويات نمطًا شائعًا لكيفية إجراء الأسلاك ، وهو مفهوم يشيرون إليه تحت الاسم العام جدًا "انعكاس التحكم". في هذه المقالة ، أقوم بالبحث في كيفية عمل هذا النمط ، تحت الاسم الأكثر تحديدًا "حقن التبعية" ، وقم بمقارنته مع بديل "محدد موقع الخدمة". الاختيار بينهما أقل أهمية من مبدأ فصل التكوين عن الاستخدام.
أحد الأشياء المسلية حول مشروع Java world هو الكم الهائل من النشاط في بناء بدائل لتقنيات J2EE السائدة ، والكثير منها يحدث في المصادر المفتوحة. الكثير من هذا هو رد فعل على تعقيد الوزن الثقيل في عالم J2EE السائد ، ولكن الكثير منه يستكشف أيضًا البدائل ويطرح أفكارًا إبداعية. هناك مشكلة شائعة يجب معالجتها وهي كيفية دمج عناصر مختلفة معًا: كيف تتوافق مع بنية وحدة التحكم في الويب هذه مع دعم واجهة قاعدة البيانات هذه عندما تم إنشاؤها من قبل فرق مختلفة مع القليل من المعرفة ببعضها البعض. اتخذ عدد من الأطر طعنة في هذه المشكلة ، والعديد منها يتفرع لتوفير قدرة عامة على تجميع المكونات من طبقات مختلفة. وغالبًا ما يشار إلى هذه الحاويات بأنها خفيفة الوزن ، وتشمل الأمثلة PicoContainer و Spring.

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

المكونات والخدمات

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

أستخدم مكونًا يعني وجود مجموعة من البرامج المخصصة للاستخدام ، دون تغيير ، من خلال تطبيق خارج عن سيطرة كتّاب المكون. يعني "بدون تغيير" أن التطبيق الذي يستخدم لا يغير الكود المصدري للمكونات ، على الرغم من أنه قد يغير سلوك المكون عن طريق توسيعه بطرق يسمح بها كتّاب المكون.
تشبه الخدمة مكوّنًا في استخدامه من قبل التطبيقات الأجنبية. الفرق الرئيسي هو أنني أتوقع أن يتم استخدام مكون محليًا (فكر في ملف jar أو التجميع أو dll أو الاستيراد المصدر). سيتم استخدام الخدمة عن بُعد من خلال بعض الواجهات البعيدة ، إما متزامن أو غير متزامن (مثل خدمة الويب أو نظام الرسائل أو RPC أو المقبس.)

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

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

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