سؤال

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

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

المحلول

مذا عن هذه؟

HashMap<Integer, Runnable> map = new HashMap<Integer, Runnable>();
map.put(Register.ID, new Runnable() { 
    public void run() { functionA(); }
});
map.put(NotifyMessage.ID, new Runnable() { 
    public void run() { functionB(); }
});
// ...
map.get(id).run();

(إذا كنت بحاجة إلى اجتياز بعض الوسائط، فحدد واجهتك الخاصة وظيفة لها معلمة مناسبة واستخدامها بدلا من Runnable).

نصائح أخرى

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

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

public interface PacketProcessor
{
    public void processPacket(Packet packet);
}

...

PacketProcessor doThing1 = new PacketProcessor()
{
    public void processPacket(Packet packet)
    {
        // do thing 1
    }
};
// etc.

// Now doThing1, doThing2 can be used like function pointers for a function taking a
// Packet and returning void

هل سبق لك أن استخدمت Swing / Awt؟ التسلسل الهرمي للحدث يحل مشكلة مماثلة. الطريقة التي يمر بها Java يدور حول واجهة، على سبيل المثال

public interface ActionHandler {
    public void actionPerformed(ActionArgs e);
}

ثم، إذا كنت ترغب في تعيين أعداد صائط الأعداد الصحيحة على هذه الكائنات، فيمكنك استخدام شيء مثل java.util.HashMap<Integer,ActionHandler> لإدارة ذلك. يمكن أن تذهب التطبيقات الفعلية إما في فصول مجهولة (أفضل تقريب جافا "Lambda") أو في الفصول المناسبة في مكان ما. إليك طريقة الفصل المجهول:

HashMap<Integer,ActionHandler> handlers;
handlers.put(ACTION_FROB, new ActionHandler() {
    public void actionPerformed(ActionArgs e) {
        // Do stuff
        // Note that any outer variables you intend to close over must be final.
    }
});
handlers.get(ACTION_FROB).actionPerformed(foo);

(تحرير) إذا كنت تريد أن تكون أكثر مسيئة، يمكنك تهيئة Hashmap مثل ذلك:

HashMap<Integer,String> m = new HashMap<Integer,String>() {{
    put(0,"hello");
    put(1,"world");
}};

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

يحصل المفوض C # (MulticastDelegate) أن يكون صحيحا) على المعلومات من استخدام الأسلوب MethodInfo الذي هو نفس الشيء الذي تحتاجه للقيام به من أجل فئة المفوض باستخدام java.lang.reflect.method. قمت بنشر الرمز الخاص بي لفصل المفوض (T) على شكل آخر من هذا الموقع يتعامل مع هذه المشكلة البالية. أقوم بذلك لأن (نعم) يجري من C ++ أحتاج إلى طريقة أفضل لمرور الوظائف (خاصة الفراغ) ثم الاضطرار إلى إنشاء واجهة لعملية أو أكثر. الآن يمكنني اختيار الوظيفة تعبئة معلومات المعلمة لذلك. Voila`! لطيفة صالحة للاستخدام مع عدم وجود تفقد ملحوظ في السرعة من الجب أو JVM. وإذا كانت قد تعلمت فقط برمجة Java لمدة أسبوع فقط، فيمكن لأي مبرمج Java القيام بذلك.

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

يمكنك واجهة طرق ثابتة. تتيح لك هذه الطريقة تحديد المعلمات أيضا. أعلن واجهة الخاص بك ...

public interface RouteHandler {
    void handleRequest(HttpExchange t) throws IOException;
}

وخره ...

private Map<String, RouteHandler> routes = new HashMap<>();

ثم قم بتنفيذ الأساليب الثابتة التي تتطابق مع الواجهة / Params ...

public static void notFound(HttpExchange t) throws IOException {
    String response = "Not Found";

    t.sendResponseHeaders(404, response.length());
    OutputStream os = t.getResponseBody();
    os.write(response.getBytes());
    os.close();
}

يمكنك بعد ذلك إضافة تلك الأساليب إلى خريطتك ...

routes.put("/foo", CoreRoutes::notFound);

واتصل بهم على النحو التالي ...

RouteHandler handler = routes.get("/foo");
handler.handleRequest(exchange);

آخر إبرة مماثلة يمكن أن يستخدم خراطيم Java 8:

Map<Integer, Supplier<T> suppliers = new HashMap();
suppliers.put(1, () -> methodOne());
suppliers.put(2, () -> methodTwo());

// ...

public T methodOne() { ... }
public T methodTwo() { ... }

// ...

T obj = suppliers.get(id).run();

يمكنك القيام بذلك من خلال استخدام نمط سلسلة المسؤولية.

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

هناك بعض Gotchas، مثل، فهو ينتشر المنطق الخاص بك، يمكن أن تسبب سلسلة طويلة بشكل مفرط مشاكل في الأداء. ولكن مع هذه gotchas لديك فائدة من زيادة الاستقرار، وتماسك أقوى. كما لا تقتصر على التعبيرات باستخدام تعبيرات ENUM و BYTE و INT قصيرة ومثابة الزناد للتفرعين.

تحقق من إغلاق كيفية تنفيذها في مكتبة Lambdaj. لديهم بالفعل سلوك مشابه جدا من المندوبين C #:

http://code.google.com/p/lambdaj/wiki/closures.

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