البرمجة في لغة:ما هو أجمل طريقة تحديد الاسترجاعات في جافا ؟

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

  •  03-07-2019
  •  | 
  •  

سؤال

في كتاب 'رمز كاملة' يتحدث المؤلف عن البرمجة في لغة (بدلا من البرمجة بلغة).إنه يعني أنه يجب أن لا تحد نفسك من القيود المفروضة على اختيار لغة البرمجة.

رد هو غالبا ما تستخدم ميزة.أنا مهتم:ما هو أجمل طريقة البرنامج لل رد في جافا-لغة ؟

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

المحلول

تحقق من هذه المادة:

http://www.onjava.com/pub/a/onjava/2003/05/21/delegates.html

رد أساسا حالة خاصة od المندوبين (مثل C# لها), و المادة يعطي تنفيذ ما يشبه C# مندوب في جافا.

نصائح أخرى

جافا يستخدم كل أنواع الاستدعاء لجميع أنواع الحالات.منذ أقدم الأيام الخوالي من AWT المستمعين ، فقد كان جافا عن كل رد.

هناك نوعان الأساسي "النكهات" جافا رد.الأول هو تنفيذ واجهة الطريقة:

public class MyThing implements StateChangeListener {

   //this method is declared in StateChangeListener
   public void stateChanged() {
      System.out.println("Callback called!");
   }

   public MyThing() {
      //Here we declare ourselves as a listener, which will eventually
      //lead to the stateChanged method being called.
      SomeLibraryICareAbout.addListener(this);
   }
}

الثاني نكهة جافا رد هو الطبقة الداخلية من مجهول:

public class MyThing {

   public MyThing() {
      //Here we declare ourselves as a listener, which will eventually
      //lead to the stateChanged method being called.
      SomeLibraryICareAbout.addListener( new StateChangeListener() {
          //this method is declared in StateChangeListener
          public void stateChanged() {
              System.out.println("Callback called!");
          }
      });
   }
}

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

الطريقة الأكثر شيوعا رأيت للتغلب absense من مؤشرات الدالة/المندوبين في جاوة هو استخدام functors.

في الأساس, تعريف واجهة واحدة طريقة استخدام مثيلات كما رد:

public interface Callback<T,V>{
  public T invoke(V context);
}

الكثير أكثر مطول من C/C++ أو C# حكمه ، لكنه يعمل.مثال على هذا النمط في المكتبة القياسية هو المقارنة واجهة.

للأسف, في جافا, وظائف ليست كائنات من الدرجة الأولى.أفضل ما يمكنك فعله هو استخدام واجهة:

public interface MyCallback
{
    public void theCallback(int arg);
}

public class Sample
{
    public static void takesACallback(MyCallback callback)
    {
        ...
        callback.theCallback(arg);
    }
}

public class Sample2
{
    public static void main(String[] args)
    {
        Sample.takesACallback(new MyCallback()
        {
            void theCallback(int arg)
            {
                // do a little dance
            }
        });
    }
}

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

إلقاء نظرة على http://java.sun.com/docs/books/tutorial/uiswing/events/actionlistener.html

كنت في كثير من الأحيان توفير مثيل مجهول الدرجة تنفيذ واجهة مناسبة مماثلة

listener = new ActionListener() {
  public void actionPerformed(ActionEvent e) {
     // do stuff...
  }
};

حيث كنت ثم تمرير المستمع مناسب البديل الأسلوب.

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

الاستفادة من هذا النهج هو أنه genericity.وكان الهدف هو أن تكون قادرا على الكتابة API مثل نظام الملفات شجرة المشي دون الحاجة إلى تعريف واجهة كل الوقت, بدلا من ذلك تعيين طريقة في التعليمات البرمجية باستخدام API لأداء العمل.

على سبيل المثال, المشي ملف النظام شجرة معالجة كل ملف:

عملية شجرة الدليل API

/**
 * Process a directory using callbacks.  To interrupt, the callback must throw an (unchecked) exception.
 * Subdirectories are processed only if the selector is null or selects the directories, and are done
 * after the files in any given directory.  When the callback is invoked for a directory, the file
 * argument is null;
 * <p>
 * The callback signature is:
 * <pre>    void callback(File dir, File ent);</pre>
 * <p>
 * @return          The number of files processed.
 */
static public int processDirectory(File dir, Callback cbk, FileSelector sel) {
    return _processDirectory(dir,new Callback.WithParms(cbk,2),sel);
    }

static private int _processDirectory(File dir, Callback.WithParms cbk, FileSelector sel) {
    int                                 cnt=0;

    if(!dir.isDirectory()) {
        if(sel==null || sel.accept(dir)) { cbk.invoke(dir.getParent(),dir); cnt++; }
        }
    else {
        cbk.invoke(dir,(Object[])null);

        File[] lst=(sel==null ? dir.listFiles() : dir.listFiles(sel));
        if(lst!=null) {
            for(int xa=0; xa<lst.length; xa++) {
                File ent=lst[xa];
                if(!ent.isDirectory()) {
                    cbk.invoke(dir,ent);
                    lst[xa]=null;
                    cnt++;
                    }
                }
            for(int xa=0; xa<lst.length; xa++) {
                File ent=lst[xa];
                if(ent!=null) { cnt+=_processDirectory(ent,cbk,sel); }
                }
            }
        }
    return cnt;
    }

باستخدام عملية الدليل API

مع الأسلوب أعلاه مكتوبة, يمكنني الآن بسهولة جدا عملية شجرة الدليل لأي العملية ؛ المسح الضوئي, عد, قائمة, الخ.مع تغيير طفيف في الاحتجاج رد على دليل سواء قبل أو بعد تنازلي العمليات مثل ملف/شجرة الحذف يمكن أيضا أن يتم (معلمة إضافية هو في حاجة إلى الإشارة إلى ما قبل/ما بعد الطبيعة من الاحتجاج).

static private final Method             COUNT =Callback.getMethod(Xxx.class,"callback_count",true,File.class,File.class);

...

IoUtil.processDirectory(root,new Callback(this,COUNT),selector);

...

private void callback_count(File dir, File fil) {
    if(fil!=null) {                                                             // file is null for processing a directory
        fileTotal++;
        if(fil.length()>fileSizeLimit) {
            throw new Abort("Failed","File size exceeds maximum of "+TextUtil.formatNumber(fileSizeLimit)+" bytes: "+fil);
            }
        }
    progress("Counting",dir,fileTotal);
    }
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top