Как я могу заставить метод экземпляра интерфейса принимать аргументы только одного и того же класса? - PullRequest
8 голосов
/ 01 марта 2011

Я хочу использовать такой интерфейс:

public interface ResultItem {
    public int getConfidence();
    public boolean equals(ResultItem item);
    public ResultItem cloneWithConfidence(int newConfidence);
}

Я реализовал его с помощью различных объектов, представляющих результат распознавания голоса.

Идея в том, что я хочу сравнить только результаты одного и того же вида. То есть, если я создаю класс IntResult, реализующий ResultItem, я хочу, чтобы сигнатуры методов стали:

public boolean equals(IntResult item);
public IntResult cloneWithConfidence(int newConfidence);

Я чувствую, что в моем интерфейсе есть недостаток дизайна, потому что сейчас я использую довольно уродливые преобразования в результаты cloneWithConfidence и других методов, возвращающих ResultItem.

Есть ли лучший способ?

Ответы [ 3 ]

11 голосов
/ 01 марта 2011

Существует часто встречающаяся идиома, которая выглядит следующим образом:

public interface ResultItem<T extends ResultItem<T>> {
    public int getConfidence();
    public boolean equals(T item);
    public T cloneWithConfidence(int newConfidence);
}

public class IntResult implements ResultItem<IntResult> {
  //...
}
4 голосов
/ 01 марта 2011

Не совсем ответ на ваш вопрос, но важное замечание (я думаю):

Если вы хотите, чтобы ваш метод equals был применим для объектов в коллекциях и тому подобном, вам нужно реализовать public boolean equals(Object o), и он должен работать для сравнения со всеми видами объектов (хотя в большинстве случаев он возвращает false). Вы можете дополнительно иметь метод с более узким типом параметра, а в реализациях делегировать его так:

public class IntResult {
    public boolean equals(Object o) {
        return o instanceof IntResult &&
             this.equals((IntResult)o);
    }
    public boolean equals(IntResult that) {
        // TODO
    }

}

Убедитесь, что вы выполняете все условия в контракте равных, а именно: симметрию, рефлексивность, транзитивность и наличие совместимой реализации hashCode.

1 голос
/ 01 марта 2011

Ну, вы могли бы сделать его универсальным:

public interface ResultItem<T extends ResultItem<T>> {
    public boolean equals(ResultItem<T> item);
}

Тогда вам нужно будет IntResult реализовать ResultItem<IntResult>.

Конечно, это не мешает другому классуплохо себя ведет, например, FloatResult реализует ResultItem<IntResult>, но он заставляет различные биты API работать, когда все классы ведут себя хорошо.

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