Адаптер от интерфейса <Type>к интерфейсу <Subtype> - PullRequest
2 голосов
/ 13 сентября 2011

Рассмотрим следующий интерфейс.

public interface Feed<T> {

    public void put( T o );

}

У нас есть простой Java-класс, реализующий этот интерфейс, который записывает объекты в определенную коллекцию.

public class CollectionFiller<T> implements Feed<T> {

    private final Collection<T> collection;

    private CollectionFiller( Collection<T> collection ) {
        this.collection = collection;
    }

    public void put( T o ) {
        this.collection.add( o );
    }

    public static <T> CollectionFiller<T> of( Collection<T> collection ) {
        return new CollectionFiller<T>( collection );
    }

}

Теперь мы определим два фиктивных класса, чтобы конкретизировать вопрос.

public class Super {}

public class Sub extends Super {}

Допустим, есть некоторый метод writeSubsTo( Feed<Sub> f ), и у нас есть экземпляр cf из CollectionFiller<Super>.Поскольку cf только добавляет объекты в свою коллекцию "Supers", было бы безопасно передать его в writeSubsTo.Однако компилятор этого не допустит.(Причина такого поведения мне ясна.)

Я хотел написать вспомогательный адаптер, который обернут вокруг CollectionFiller типа X и представляет собой Feed определенного подтипа типа X.Я попробовал (среди прочего) следующее, но компилятор доставляет мне проблемы.

class SubFiller<T1, T2 extends T1> implements Feed<T2> {

    private final CollectionFiller<T1> collectionFiller;

    SubFiller( CollectionFiller<T1> collectionFiller ) {
        this.collectionFiller = collectionFiller;
    }

    public void put( T2 o ) {
        this.collectionFiller.put( o );
    }

    public static <T1, T2 extends T1> SubFiller<T1, T2> of( CollectionFiller<T1> c ) {
        return new SubFiller<T1, T2>( c );
    }

}

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

CollectionFiller<Super> cf = CollectionFiller.of( new HashSet<Super>() );
SubFiller<Super, Sub> sf = SubFiller.of( cf );
writeSubsTo( SubFiller.of( cf ) );

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

1 Ответ

7 голосов
/ 13 сентября 2011

Если вы используете writeSubsTo(Feed<? super Sub> f), тогда вы можете передать Feed<Super>. Тогда вы можете полностью отказаться от своих классов наполнителя. Yay для контравариантности! : -Р

(Существует также ковариантная версия, ? extends X, для случаев, когда вы выводите значения, а не вводите значения.)

...