في الآونة الأخيرة ، تعرضت دائمًا لمبادئ البرمجة أو أنماط مثل IOC (انعكاس التحكم) ، DI (حقن التبعية) ، وهذه هي جوهر ربيع أطر Java الشهيرة ، الدعامات ، وما إلى ذلك. بعد قراءتها ، لدي بعض الفهم. الآن سأجمع بين التفسيرات في الكتاب ومعالجتي الخاصة وفرزها على النحو التالي:
EG1
وصف المشكلة:
قم بتطوير نظام يمكنه إنشاء تقارير بتنسيق Excel أو PDF وفقًا لمتطلبات مختلفة ، مثل التقارير اليومية والتقارير الشهرية وما إلى ذلك.
حل:
وفقًا لمبدأ "البرمجة الموجهة للواجهة" ، يجب فصل الواجهة والتنفيذ ، أي أن وظيفة توليد التقارير يتم استخراجها في تقرير تقرير عام عن الواجهة ، ويتم توفير تطبيقين يولدون تقارير Excel و PDF بتنسيقات Excel و PDF. يحصل العميل بعد ذلك على وظيفة طباعة التقرير المقابلة من خلال خدمة خدمة مزود الخدمة.
طريقة التنفيذ:
وفقًا لما ورد أعلاه ، يتم الحصول على مخطط الفصل التالي:
تنفيذ الكود:
interface reportGenerator {public void توليد (جدول الجدول) ؛ } class excelgenerator تنفذ ReportGenerator {public void توليد (جدول الجدول) {system.out.println ("إنشاء تقرير excel ...") ؛ }} class pdfgenerator تنفذ ReportGenerator {public void توليد (جدول الجدول) {system.out.println ("إنشاء تقرير pdf ...") ؛ }} Class Reportservice {// مسؤول عن إنشاء مولد التقرير عن احتياجات محددة من المولد الخاص بـ reportGenerator = جديد pdfgenerator () ؛ // private static reportgenerator generator = new Excelgenerator () ؛ public void getDailyReport (Date Date) {table.setDate (date) ؛ // ... generator.generate (table) ؛ } public void getMonthlyReport (month month) {table.setMonth (month) ؛ // ... generator.generate (table) ؛ }} client client {public static void main (string [] args) {ReportService ReportService = New Reportservice () ؛ ReportService.getDailyReport (New Date ()) ؛ //reportservice.getMonthlyReport(new Date ()) ؛ }}
EG2
وصف المشكلة:
كما هو موضح في التعليقات الواردة في الكود أعلاه ، يتم إنشاء مولد التقرير المحدد بواسطة مرمز داخليًا في فئة التقارير ، بحيث تعتمد التقارير مباشرة على PDFGenerator أو Excelgenerator ، ويجب القضاء على هذا الاقتران الضيق الواضح.
الحل: أدخل الحاويات لإدخال مدير وسيط ، أي الحاوية (الحاوية) ، والتي تدير بشكل موحد الكائنات المشاركة في نظام التقارير (فيما يلي مكون ، نسميها فول) ، بما في ذلك تقارير تقارير ومختلف XXGenerators. هنا تستخدم مثيل HashMap في شكل زوج من القيمة الرئيسية لحفظ هذه الفاصوليا.
طريقة التنفيذ:
يتم الحصول على مخطط الفصل على النحو التالي:
تنفيذ الكود:
حاوية الفئة {// حفظ مكونات مختلفة مطلوبة في أزواج القيمة الرئيسية بين الخريطة الثابتة الخاصة <String ، Object> Beans ؛ الحاوية العامة () {beans = new HashMap <string ، Object> () ؛ // إنشاء وحفظ تقرير تقرير محدد تقرير reportGenerator = جديد pdfgenerator () ؛ Beans.put ("ReportGenerator" ، ReportGenerator) ؛ // الحصول على وإدارة مرجع التقارير التقارير التقارير = New Reportservice () ؛ Beans.put ("Reportservice" ، ReportService) ؛ } كائن ثابت عام getBean (معرف السلسلة) {return Beans.get (id) ؛ }} Class Reportservice {// القضاء على علاقة الاقتران الضيقة واستبدلها بحاوية // private static reportgenerator generator = new pdfgenerator () ؛ مولد Generator الخاص بالتقرير الخاص = (ReportGenerator) Container.getBean ("ReportGenerator") ؛ public void getDailyReport (Date Date) {table.setDate (date) ؛ generator.generate (الجدول) ؛ } public void getMonthlyReport (month month) {table.setMonth (month) ؛ generator.generate (الجدول) ؛ }} client client {public static void main (string [] args) {container container = new Container () ؛ ReportService ReportService = (ReportService) Container.getBean ("ReportService") ؛ ReportService.getDailyReport (New Date ()) ؛ //reportservice.getMonthlyReport(new Date ()) ؛ }}
مخطط التوقيت تقريبًا على النحو التالي:
تأثير:
كما هو موضح أعلاه ، لم تعد تقارير خدمة التقارير مرتبطة بشكل مباشر بمؤلف التقرير المحدد. لقد استخدمت الحاويات لعزل الواجهة والتنفيذ ، وتحسين قابلية إعادة استخدام حبوب مكون النظام. في هذا الوقت ، يمكنك أيضًا استخدام ملفات التكوين للحصول على تعريف مكونات محددة في الحاوية في الوقت الفعلي.
EG3
وصف المشكلة:
ومع ذلك ، إذا نظرت إلى مخطط الفئة أعلاه ، فمن السهل أن تجد أن هناك علاقة ثنائية الاتجاه بين Reportservice والحاوية ، ولديها تبعيات متبادلة. وإذا كنت ترغب في إعادة استخدام ReportService ، فإنه يعتمد بشكل مباشر أيضًا على منطق البحث المحدد لحاوية واحدة. إذا كانت الحاويات الأخرى لها آليات بحث مكونات مختلفة (مثل JNDI) ، فإن إعادة استخدام Reportservice في هذا الوقت يعني أن منطق البحث الداخلي للحاوية يحتاج إلى تعديل.
الحل: تقديم محدد موقع الخدمة
يتم إعادة إدخال موقع محدد موقع خدمة الطبقة غير المباشرة لتوفير واجهة لمنطق البحث عن المكونات. يرجى الاطلاع على الوصف في ويكيبيديا أو وصفها من قبل Java EE 1 و 2. وهذا سيمكن من العزلة المحتملة للتغييرات المحتملة.
طريقة التنفيذ:
مخطط الفصل هو كما يلي:
تنفيذ الكود:
// في التطبيق الفعلي ، يمكنك استخدام واجهة لتوفير حاوية حاوية ثابتة من فئة الواجهة الموحدة Public Static ReportGenerator GetReportGenerator () {return (ReportGenerator) Container.getBean ("ReportGeneraator") ؛ }} Class Reportservice {private reportGenerator reportGenerator = serviceLocator.getReportGenerator () ؛ // ...}EG4
وصف المشكلة:
ومع ذلك ، سواء كان ذلك تقديم حاوية أو باستخدام محدد موقع الخدمة ، فإن "التقارير" نشطة في البحث وإنشاء مكونات محددة ، مما يعني أنه كعميل ، يجب أن تكون خدمة التقارير واضحة حول ما يحتاجه ، ومكان الحصول عليه ، وكيف يمكن الحصول عليها. يجب إضافة تفاصيل منطقية مفاجئة ومحددة بسبب ماذا وأين وكيف.
على سبيل المثال ، في طريقة التنفيذ السابقة لـ "تقديم الحاوية" ، هناك الرمز التالي:
Class Reportservice {// القضاء على علاقة الاقتران الضيقة واستبدلها بحاوية // private static reportgenerator generator = new pdfgenerator () ؛ // Find Private ReportGenerator Generator = (ReportGenerator) Container .GetBean ("ReportGenerator") ؛
في طريقة تنفيذ "تقديم محدد موقع الخدمة" ، هناك الكود التالي:
Class ServiceLocator {privatestatic Container Container = New Container () ؛ PublicStatic ReportGenerator GetReportGenerator () {// لا يزال حاوية. getBean () ، يتم استخدام مندوب فقط (ReportGenerator) Container.getBean ("ReportGeneraator") ؛ }} Class Reportservice {// Reportservice في النهاية ، لا يزال البحث "بفعالية" للبحث والمندوبين إلى ServiceLocator Private ReportGenerator Streortgenerator = ServiceLocator.getReportGenerator () ؛ }
حل:
في هذه الحالة ، فإن تغيير "النشط" إلى "السلبي" سيقلل بلا شك المعرفة الداخلية لتقارير خدمة التقارير (أي منطق العثور على المكونات). وفقًا لمبدأ انعكاس التحكم (IOC) ، يتم تحويل هذا السحب (السحب ، النشط) إلى وضع الدفع (الدفع ، السلبي).
على سبيل المثال ، يعد اشتراك RSS الذي نستخدمه عادة تطبيقًا للدفع ، مما يوفر لنا متاعب تسجيل الدخول إلى موقعنا المفضل عدة مرات في اليوم للحصول على تحديثات المقالة بنشاط.
حقن التبعية (DI) يحقق هذا النوع من الاستقبال السلبي ويقلل من مشاكل العملاء (هنا ، التقارير) نفسها التي تحتوي على منطق معقد ومعرفة الكثير.
طريقة التنفيذ:
لأننا نريد أن نكون حفل استقبال "سلبي" ، يجب أن نعود إلى مثال الحاوية دون استخدام وضع محدد الخدمة. يتم الحصول على مخطط الفئة المعدلة من هذا على النحو التالي:
مخطط الفصل الأصلي هو كما يلي. يمكنك التحقق من ذلك والانتباه إلى مطالبات التعليق:
تنفيذ الكود:
من أجل تمكين المثال المطلوب تجميعه وتشغيله ، واستخدام نتائج تشغيل رمز التتبع لتثبيت مخطط الفئة بالكامل بشكل صريح والتعاون مع بعضها البعض بالتسلسل ، تمت إضافة العديد من البيانات المطبوعة المرقمة وفئتين غير مهمتين إلى مُنشئ كل فئة ، وهو أمر مهم ، على النحو التالي:
استيراد java.util.date ؛ استيراد java.util.hashmap ؛ استيراد java.util.map ؛ // من أجل أن تكون قادرًا على تجميع وتشغيل ، هناك فئتان إضافيتان. جدول الفصل {} جدول الفئة {publicvoid setDate (تاريخ التاريخ) {} publicvoid setMonth (شهر الشهر) {}} // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- من Excelgenerator ... ") ؛ } publicvoid توليد (جدول الجدول) {system.out.println ("إنشاء تقرير excel ...") ؛ }} class pdfgenerator تنفذ ReportGenerator {public pdfgenerator () {system.out.println ("2 ... ابدأ تهيئة pdfgenerator ...") ؛ } publicvoid توليد (جدول الجدول) {system.out.println ("إنشاء تقرير pdf ...") ؛ }} // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- الحصول على وإدارة مرجع التقارير التقارير تقارير = جديد تقارير () ؛ // حقن مثيل ReportGenerator المحدد الذي تم إنشاؤه أعلاه ReportService.setReportGenerator (ReportGenerator) ؛ Beans.put ("Reportservice" ، ReportService) ؛ System.out.println ("5 ... end initialization Container ...") ؛ } publicstatic Object getBean (string id) {system.out.println ("آخر مكون خدمة ... getBean () ->" + id + "...") ؛ returnbeans.get (id) ؛ }} Class Reportservice {// private static reportgenerator generator = new pdfgenerator () ؛ . // قم بإزالة البحث "النشط" أعلاه وتوفير حقول خاصة لحفظ مولد ReportGenerator الخاص بكائن تم حقنه خارجيًا ؛ // حقن publicvoid من الخارج في نموذج setter setReportGenerator (مولد ReportGenerator) {system.out.println ("4 ... ابدأ عن حقن reportGenerator ...") ؛ this.generator = مولد ؛ } جدول الجدول الخاص = جدول جديد () ؛ Public Reportservice () {system.out.println ("3 ... ابدأ التهيئة ReportService ...") ؛ } publicvoid getDailyReport (تاريخ التاريخ) {table.setDate (date) ؛ generator.generate (الجدول) ؛ } publicvoid getMonthlyReport (month month) {table.setMonth (month) ؛ generator.generate (الجدول) ؛ }} publicClass Client {publicstaticvoid main (string [] args) {// تهيئة الحاوية الجديدة () ؛ ReportService Reportservice = (ReportService) Container .getBean ("ReportService") ؛ ReportService.getDailyReport (New Date ()) ؛ // ReportService.getMonthlyReport (Date ()) ؛ }}
نتائج التشغيل:
1 ... ابدأ تهيئة حاوية ... 2 ... ابدأ تهيئة PDFGenerator ... 3 ... ابدأ التقارير التهيئة ... 4 ... ابدأ عن حقن ReportGenerator ... 5 ... حاوية تهيئة النهاية ... أخيرًا احصل على مكون الخدمة ... GetBean () -> Reportservice ... إنشاء تقرير PDF ...
يلاحظ:
1. وفقًا لترتيب طباعة نتائج التشغيل أعلاه ، يمكن ملاحظة أن الرقم المحدد المضافة إلى الكود معقول ، والذي يحاكي عملية تنفيذ البرنامج ، لذلك لم يعد يرسم مخططات التسلسل.
2. لاحظ أن استخدام IOC و DI في هذا المثال يعتمد على تقارير المحرك كعميل (أي مكون مكون) ، ورمز الاختبار في فئة العميل الرئيسية () في الكود هو المستخدم النهائي لمكون الخدمة ، ولكن ما يحتاجه ليس المكون ، ولكن الخدمات التي يتمتع بها المكون.
3. في الواقع ، في مقطع مربع الربيع ، من الواضح أن تهيئة الحاوية ليس ما يجب أن يفعله عميل المستخدم النهائي ، وينبغي أن يبدأ مقدمًا من قبل مزود الخدمة.
4. في عميل المستخدم النهائي ، ما زلنا نستخدم ContaBean.getBean ("ReportService") للحصول على مكونات الخدمة التي تم إنشاء مثيل لها في مُنشئ الحاويات مقدمًا. في تطبيقات محددة ، عادة ما يتم نشر مكونات الخدمة المتاحة على الخادم باستخدام XML وملفات التكوين الأخرى ، ثم تتم قراءة ملفات التكوين بواسطة الحاوية ودمجها مع تقنية الانعكاس لإنشاء مكونات خدمة محددة وحقنها.
تحليل:
في السابق ، طلبت شركة ReportService بنشاط مكون الخدمة من الحاوية ، ولكن الآن انتظرت بشكل سلبي لحقن الحاويات (حقن ، أي ، دفع) مكون. من الواضح أن التحكم يتم نقله من الوحدة النمطية الأساسية (تقارير المحفوظات هي مكون مكون) إلى الوحدة النمطية عالية المستوى (الحاوية هي موفر المكون) ، أي يتم عكس التحكم.