بدون مؤشرات الوظائف، ما هي الطريقة الموصى بها لتنفيذ رد الاتصال في Java - بخلاف الواجهات؟

StackOverflow https://stackoverflow.com/questions/626669

  •  06-07-2019
  •  | 
  •  

سؤال

لدي فصلان يرغبان في تمرير بعض المعلومات لبعضهما البعض ويتم الاتصال بهما لاحقًا باستخدام تلك المعلومات (نمط رد الاتصال).

ضمن طلبي، تخدم هذه الآلية غرضين:

  • التنفيذ المقرر / المؤجل
  • التنفيذ غير المتزامن الذي يتضمن المراسلة

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

الآن، إذا كانت هناك مؤشرات وظيفية (أو ما يعادلها) في Java، فسأقوم بتنفيذ بعض فئات "الوظيفة" التي تحتوي على واحدة بالإضافة إلى الوسيطات التي تحتاجها.على سبيل المثال، في PHP، يجب أن تقوم هذه البنية بتخزين اسم فئة واسم وظيفة ومجموعة من الوسائط.في لغة C، سيكون مؤشرًا للوظيفة ويجب أن أجعل الوسيطات بنفس العدد والنوع لجميع المكالمات.

في Java، الأسلوب المعتاد هو أن يكون لديك واجهة يتم تنفيذها بواسطة جميع الفئات التي تريد أن يتم استدعاؤها مرة أخرى، مثل هذا:

public interface ICallable {
    public void call_me(Object data);
}

الآن هذا لن ينجح معي، لأن

  • قد يكون للكائنات التي سيتم استدعاؤها مرة أخرى مجموعة مختلفة من الطرق لتلقي المكالمة
  • المتصل ليس هو من يقرر المكالمة التي يجب إجراؤها

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

ما هو نمط التصميم الجيد للتعامل مع هذا الموقف في Java؟

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

المحلول

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

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

   sender.addListener(new ListenerInterface()
   {
      public void callback(Object arg)
      {
         handlerFunction(arg);
      }
   });

نصائح أخرى

يمكن أن تستخدم مفهومًا مشابهًا لـ الطبقات الداخلية المجهولة

مرجع آخر هنا

سأستخدم واجهة، كما وصفتها، ثم استخدم فئة مجهولة لعمليات الاسترجاعات الخاصة بك.على سبيل المثال، من داخل المتصل الخاص بك:

ICallback callback = new ICallback() { 
    public void call_me(Object data) { this.actionToCall(data); }
}
serverObject.doX(callback);

(قد يكون بناء الجملة مختلفًا قليلاً عن ذلك.)

وبهذه الطريقة يمكنك أن تحدد للمتصل الأصلي (عند نقطة المكالمة) الإجراء الذي يجب اتخاذه عند الانتهاء.

إذا كنت لا تريد حقًا استخدام الواجهات (وثق بي أنك تريد ذلك!) يمكنك استخدام الانعكاس للحصول على الطريقة التي تريد الاتصال بها ثم تمريرها إلى الطريقة التي تحتاج إلى إجراء الاتصال.هذا أقرب ما يكون إلى مؤشر دالة C الذي ستحصل عليه.

سيكون الانعكاس أبطأ (على الأرجح) من طريقة الواجهة للقيام بذلك (لكن هذا لن يهم إلا إذا تم استدعاؤه بشكل متكرر).

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

سيكون الانعكاس رمزًا أقبح من طريقة الواجهة للقيام بذلك أيضًا.

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

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

ربما أسيء فهم المشكلة، ولكن يبدو لي أنك ستستفيد من إعداد نوع ما من نظام الأحداث.

تقوم بشكل أساسي بإعداد معالج الحدث والفئات التي ترغب في معرفتها حول الحدث تشترك في معالج الحدث.لذا، بالنسبة لمشكلتك، عند الانتهاء من X، سيتم إطلاق FinishedProcessingEvent() الذي سيكون كائنك مشتركًا فيه.عندما يتلقى كائنك هذا الحدث (مع أي مشتركين آخرين يهتمون بالحدث)، فسوف يقوم بالإجراء المناسب (Y مع Z).يتم تعريف هذه الإجراءات داخل الكائنات بحيث يمكن للكائنات المختلفة القيام بأشياء مختلفة بناءً على نفس الأحداث.

هل هذا يساعد؟

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

لم ألقي نظرة عليه كثيرًا، لكن Java 5+ مستقبل قد تكون الواجهة (أو واجهاتها الفرعية) مفيدة لهذا الغرض.

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