Лучшая идиома с классным замыканием, заменяющая внутренние классы Java? - PullRequest
0 голосов
/ 17 апреля 2009

Как плохо знакомый с Groovy ...

Я пытаюсь заменить java-идиому для прослушивателей событий, фильтров и т. Д.

Мой рабочий код в Groovy следующий:

def find() {
    ODB odb = ODBFactory.open(files.nodupes); // data nucleus object database
    Objects<Prospect> src = odb.getObjects(new QProspect());

    src.each { println it };

    odb.close();

}

class QProspect extends SimpleNativeQuery {
    public boolean match(Prospect p) {
        if (p.url) {
            return p.url.endsWith(".biz");
        }
        return false;
    }
}

Теперь это далеко от того, к чему я привык в java, где реализация интерфейса Query выполняется прямо внутри метода odb.getObjects (). Если бы я, где кодировать «Java», я бы, вероятно, сделал что-то вроде следующего, но это не работает:

Objects<Prospect> src = odb.getObjects( {
        boolean match(p) { 
            if (p.url) {
            return p.url.endsWith(".biz");
        }
            return false; 
        }
    } as SimpleNativeQuery);

Или лучше, я бы хотел, чтобы это было так:

 Objects<Prospect> src = odb.getObjects( 
      { it.url.endsWith(".biz") } as SimpleNativeQuery
 );

Однако, что делает Groovy, чтобы связать метод «match» с внешним контекстом скрипта и потерпеть неудачу?

Я нахожу отличную ... отличную, в любом случае, так что я буду больше узнавать об этом. Спасибо.


Что я должен был спросить, так это как мы проводим «анонимный» класс в классном стиле. Вот идиома Java:

void defReadAFile() {
    File[] files = new File(".").listFiles(new FileFilter() {
        public boolean accept(File file) {
            return file.getPath().endsWith(".biz");
        }
    });
}

Может ли groovy быть кратким без дополнительного объявления класса?

Ответы [ 3 ]

1 голос
/ 17 апреля 2009

Я считаю, что ваш реальный вопрос: «Могу ли я использовать замыкания вместо анонимных классов при вызове API-интерфейсов Java, которые не используют замыкания». И ответ однозначный "да". Это:

 Objects<Prospect> src = odb.getObjects( 
      { it.url.endsWith(".biz") } as SimpleNativeQuery
 );

должно работать. Вы пишете «Однако, что делает Groovy, чтобы связать метод« match »с внешним контекстом сценария и подвести меня». Как именно это терпит неудачу? Мне кажется, что у вас возникла простая техническая проблема, чтобы найти решение, которое является «отличным способом» и именно тем, что вы хотите работать.

1 голос
/ 17 апреля 2009

Я думаю, что это помогло бы вам получить ответы, если бы вы абстрагировали проблему так, чтобы она не опиралась на интерфейс Neodatis DB - что бросило меня в тупик, поскольку я никогда не использовал его. То, что я написал об этом ниже, основано на очень кратком анализе.

Кстати, я никогда не использовал Groovy, хотя мне нравится то, что я видел. Но, видя, что никто еще не ответил, ты застрял со мной: -)

Я думаю, что проблема (или, по крайней мере, ее часть) может заключаться в том, что вы ожидаете слишком многого от класса SimpleNativeQuery от Neodatis. Не похоже, что он даже пытается отфильтровать объекты, прежде чем добавить их в возвращенную коллекцию. Я думаю, что вместо этого вы хотите использовать org.neodatis.odb.impl.core.query.criteria.CriteriaQuery. ( Обратите внимание на «impl» в пути к пакету. Это немного нервирует меня, так как я точно не знаю, предназначен ли этот класс для использования вызывающими. Но я не вижу ничего другие классы в Neodatis, которые позволяют указывать критерии запроса.)

Но вместо того, чтобы использовать CriteriaQuery напрямую, я думаю, что вам лучше обернуть его внутри класса Groovy, чтобы вы могли использовать его с замыканиями. Итак, я думаю, что Groovy-версия вашего кода с замыканиями может выглядеть примерно так:

// Create a class that wraps CriteriaQuery and allows you 
// to pass closures.  This is wordy too, but at least it's
// reusable.

import org.neodatis.odb.impl.core.query.criteria;

class GroovyCriteriaQuery extends CriteriaQuery {
    private final c;

    QProspect(theClosure) {
         // I prefer to check for null here, instead of in match()
         if (theClosure == null) {
             throw new InvalidArgumentException("theClosure can't be null!");
         }
         c = theClosure;
    }

    public boolean match(AbstractObjectInfo aoi){
        //!! I'm assuming here that 'aoi' can be used as the actual
        //!! object instance (or at least as proxy for it.)
        //!! (You may have to extract the actual object from aoi before calling c.)
        return c(aoi);
    }
}

// Now use the query class in some random code.

 Objects<Prospect> src = odb.getObjects( 
      new GroovyCriteriaQuery(
          { it.url.endsWith(".biz") } 
      )
 )

Надеюсь, это поможет!

0 голосов
/ 17 апреля 2009

Да, спасибо, все работает.

Я также выяснил, почему SimpleNativeQuery не работает (согласно Дэну Бреслау).

Я попробовал следующее, и это сработало чудесно. Таким образом, идиома работает как ожидалось.

new File("c:\\temp").listFiles({ it.path.endsWith(".html") } as FileFilter);

Этот следующий не работает из-за интерфейса neodatis. Интерфейс не применяет метод match ()! Это упоминается только в документации, но отсутствует в файле классов:

public class SimpleNativeQuery extends AbstactQuery{

}

Objects<Prospect> src = odb.getObjects( 
  { it.url.endsWith(".biz") } as SimpleNativeQuery
);

В приведенном выше примере, поскольку SimpleNativeQuery не имеет метода match (), он не позволяет компилятору groovy определить, к какому методу в SimpleNativeQuery следует присоединить замыкание; тогда по умолчанию используется внешний скрипт Groovy.

Это мой третий день с отличным, и мне это нравится.

Обе книги великолепны: - Groovy Recipes (Скотт Дэвис) - Программирование Groovy (Venkat Subramaniam)

...