реализация интерфейса в нескольких версиях - PullRequest
3 голосов
/ 27 декабря 2010

Я пытаюсь создать класс, который реализует интерфейс из библиотеки Java. ResultSet быть конкретным, хотя конкретный интерфейс не должен иметь отношение к вопросу. (Мне нужно поместить слой поверх обычного ResultSet, который предоставляет некоторые дополнительные функции, но я бы хотел, чтобы «обычные» функции проходили через него, и у меня есть пара функций, которые должны быть в состоянии принять либо обычный ResultSet или мой "улучшенный" ResultSet.)

Моя проблема: есть ли способ сделать это так, чтобы класс успешно компилировался как в Java 5, так и в Java 6?

Существует ряд функций, объявленных в интерфейсе ResultSet в Java 6, которые возвращают объекты, не определенные в Java 5. Если я включу эти функции, мой класс не будет компилироваться в Java 5, поскольку я ссылаюсь на неопределенные типы. Но если я не включу эти функции, мой класс не будет компилироваться в Java 6, потому что я не полностью реализую интерфейс. Кажется, я застрял в чем-то вроде уловки-22. На самом деле мне не нужна ни одна из этих функций - фактически моя реализация просто выдает «не реализованное» исключение для всех из них.

Некоторые из наших программистов используют Java 5, а некоторые - Java 6. Наша производственная среда - Java 5. Я полагаю, что в более совершенном мире все мы будем использовать одну и ту же версию. Но даже если я могу изменить нашу окружающую среду, чтобы сделать эту проблему MÕÕT в этом случае, конечно, этот вопрос приходит с проектами с открытым исходным кодом. И если я изменю свой код для работы с Java 5, то когда рано или поздно мы перейдем на Java 6, класс сломается, что кажется довольно раздражающим.

Обновление

Ну, спасибо за ответы. Я скорее надеялся, что кто-нибудь скажет мне: «О, если вы просто добавите эту аннотацию или напечатаете здесь букву« W », все будет работать волшебным образом». Наверное, нет такой удачи.

Все полученные ответы (во всяком случае, по состоянию на это обновление) дают хорошие оценки, поэтому я проголосовал за все из них и присудил награду «лучший ответ» за тот, который лучше всего выражает мое разочарование. : -)

Я думаю, что моим реальным решением будет отказаться от идеи реализации ResultSet и вместо этого создать новый интерфейс, который включает в себя только функции из ResultSet, которые должны быть реализованы для работы зверя. Я нахожу это эмоционально неудовлетворительным, но, похоже, лучше, чем альтернативы.

Ответы [ 4 ]

2 голосов
/ 27 декабря 2010

Полагаю, предложение Proxy - лучший ответ, но позвольте мне добавить два соображения:

Во-первых, изменение общедоступного API путем добавления методов к интерфейсу, методы, которые зависят от классов, которых не было в предыдущих версиях, в целом является мерзостью (разработчик, реализующий этот интерфейс, как вы, неизбежно ведет беспокоиться). Эта мерзость встречается редко и ослабляется вторым соображением:

JDBC API - это, конечно, публичный API. Но не очень публично. Я имею в виду, что обычно его интерфейсы должны реализовываться только поставщиками драйверов JDBC. И в этом случае допустимо бремя иметь разные реализации для разных версий JDBC - см., Например, . То, к чему я стремлюсь, - это отговорить вас реализовать класс, который реализует / оборачивает ResultSet, за исключением очень специфических (низкоуровневых) ситуаций. В целом, плохая практика - передавать ResultSet слоям бизнеса; в типичном случае драйвер JDBC создает экземпляр ResultSet, метод DAO использует его, но никогда не возвращает его.

2 голосов
/ 27 декабря 2010

Ах да, великий провал обратной совместимости с JDBC.Вы имеете право выпустить две пинты ругательства в направлении Sun.

Я не думаю, что у вас есть какой-либо способ использовать абсолютно одинаковые классы реализации для 5 и 6. Однако не могли бы вы, сделайте что-то вроде:

abstract class JaysBaseSuperResultSet /* does not implement ResultSet */ {
    // all needed methods for java 5
}

class JaysSuperResultSetForJava6 extends JaysBaseSuperResultSet implements ResultSet {
    // all additional java 6 methods
}

class JaysSuperResultSetForJava5 extends JaysBaseSuperResultSetForJava5 implements ResultSet {
    // class body can be empty; compile this only with java 5
}

Вам понадобится немного странный процесс сборки: я думаю, что самая простая вещь - это скомпилировать все, кроме JaysSuperResultSetForJava5 с 6-компилятором, но с -target 5, а затем скомпилироватьэтот класс один с компилятором 5 или с компилятором 6, но подключенный к 5 библиотекам (что может быть сделано и может быть проще).

Затем вам понадобится фабричный класс, который определяет текущую версию и создаетэкземпляр соответствующего конкретного класса.

Затем вы можете упаковать все в один JAR.

Похоже, это будет работать?

РЕДАКТИРОВАТЬ: понял, что вы можетеделайте это с тремя классами, а не с четырьмя.

2 голосов
/ 27 декабря 2010

Я думаю, вам следует реализовать службу как JDK-прокси, используя класс Proxy .

Он существует с версии 1.3, поэтому он будет работать во всех версиях.

Синтаксис:

ResultSet rs = Proxy.newProxyInstance(
                   ResultSet.class.getClassloader(),
                   new Class[]{ResultSet.class},
                   new ResultSetInvocationHandler()
);

И ResultSetInvocationHandler будет реализацией InvocationHandler , который перехватывает некоторые методы с помощью пользовательской логики и пропускает другие через.

Вот древний учебник о механизме прокси .

1 голос
/ 27 декабря 2010

Вместо создания класса, реализующего ResultSet, оберните ResultSet в новый класс.

Одно предостережение: рассмотрите возможность использования обобщений, чтобы вернуть правильный подинтерфейс ResultSet:

public class MyWrapper<T extends ResultSet> {
    T myResultSet;

    public MyWrapper(T myResultSet) {
        this.myResultSet = myResultSet;
    }

    public T getResultSet() {
        return myResultSet;
    }

    public void setResultSet(T myResultSet) {
        this.myResultSet = myResultSet;
    }

}

(Обратите внимание, я не проверял это).

Примечание:
Создание нового класса, который реализует ResultSet, может показаться хорошей идеей на поверхности, но быстро вырождается в безумие из-за того, что ResultSet уже имеет свой собственный подинтерфейс RowSet, который, в свою очередь, имеет свой собственный подинтерфейс JdbcRowSet, который, в свою очередь, имеет свои собственные подынтерфейсы ... и в самом конце этого дерева находятся фактические объекты, которые являются частью драйвера JDBC для вашей базы данных.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...