سؤال

المشكلة: أود أن أكون قادرًا على الوصول بشكل عام في جافا أي خاصية/حقل على java ojbect على غرار كيف ستعمل لغة ديناميكية (فكر في Groovy ، JavaScript). لن أعرف في الوقت الذي أكتب فيه رمز السباكة هذا نوع الكائن الذي هو أو ما هو اسم العقار/الحقل. لكنني سأعرف اسم العقار/الحقل عندما أذهب لاستخدامه.

الحل الحالي: لقد كتبت حتى الآن فئة غلاف بسيطة تستخدم java.beans.Introspector للاستيلاء على خصائص الفول/poj Map<String, Object>. إنه خام ولكنه يعمل في حالات بسيطة.

سؤالي هل ما هي المنهجيات الأخرى للاقتراب من هذه المشكلة إلى جانب التفكير / التحويل إلى خريطة؟

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

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

تحرير 2: يبدو أن الإجابات الأكثر شعبية تنطوي على 1) الانعكاس إما مباشرة أو عبر فئات المساعدة ، و/أو 2) رسم الخرائط للواجهات التي تنفذ أعضاء الفصل المطلوب. أنا مفتون حقًا بالتعليق الذي يتحدث عن الاستفادة من Groovy. نظرًا لأن Groovy لديه تصميم بطة حقيقي وهي لغة JVM ، هل هناك طريقة لجعل مساعد بسيط في مروع ويطلق عليه من Java؟ سيكون هذا رائعًا وربما أكثر مرونة وأداء أفضل.

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

شكرًا!

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

المحلول

إذا كنت تعرف مجموعة واجهات برمجة التطبيقات التي تريد فضحها ، فقل أنك تعلم أنك تريد الوصول إلى طريقة الطول وطريقة التكرار ، يمكنك تحديد واجهة:

public interface TheInterfaceIWant {
  int length();
  void quack();
}

وتريد أن تكون قادرًا على استخدام هذه الواجهة للوصول إلى الطرق المقابلة على الحالات التي لا تنفذ هذه الواجهة ، يمكنك استخدام فئات الوكيل: http://download.oracle.com/javase/1.4.2/docs/api/java/lang/reflect/proxy.html

لذلك يمكنك إنشاء وكيل

final Object aDuck = ...;
TheInterfaceIWant aDuckWrapper = (TheInterfaceIWant) Proxy.newProxyInstance(
    TheInterfaceIWant.class.getClassLoader(),
    new Class[] { TheInterfaceIWant.class },
    new InvocationHandler() {
      public Object invoke(
          Object proxy, Method method, Object[] args)
          throws Throwable {
        return aDuck.getClass().getMethod(
            method.getName(), method.getParameterTypes()).invoke(aDuck, args);
      }
    });

ثم يمكنك استخدام الغلاف كما تفعل البط بلغة مطبوعة ديناميكيًا.

if (aDuckWrapper.length() > 0) {
  aDuckWrapper.quack();
}

فيما يلي مثال كامل طوله يطبع "Quack" أربع مرات باستخدام Wrapper:

import java.lang.reflect.*;

public class Duck {

  // The interface we use to access the duck typed object.
  public interface TheInterfaceIWant {
    int length();
    void quack();
  }

  // The underlying instance that does not implement TheInterfaceIWant!
  static final class Foo {
    public int length() { return 4; }
    public void quack() { System.out.println("Quack"); }
  }

  public static void main(String[] args) throws Exception {
    // Create an instance but cast away all useful type info.
    final Object aDuck = new Foo();

    TheInterfaceIWant aDuckWrapper = (TheInterfaceIWant) Proxy.newProxyInstance(
        TheInterfaceIWant.class.getClassLoader(),
        new Class[] { TheInterfaceIWant.class },
        new InvocationHandler() {
          public Object invoke(
              Object proxy, Method method, Object[] args)
              throws Throwable {
            return aDuck.getClass().getMethod(
                method.getName(), method.getParameterTypes()).invoke(aDuck, args);
          }
        });

    for (int n = aDuckWrapper.length(); --n >= 0;) {
      // Calling aDuck.quack() here would be invalid since its an Object.
      aDuckWrapper.quack();
    }
  }
}

نصائح أخرى

هناك طريقة أخرى واجهتها للتو والتي تربح (الانتهاكات؟) محو النوع من النوع المثير للاهتمام:

http://rickyclarkson.blogspot.com/2006/07/duck-typing-in-java-and-no-deblection.html

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

ألقِ نظرة على طرق java.lang.class وعلى API: java.lang.reflect.*

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