Проблема абстрактной фабрики обобщений Java - PullRequest
5 голосов
/ 08 февраля 2012

Я изо всех сил стараюсь сделать эту работу:

public abstract class MapperFactory<M extends TaskMapper<? extends Message, ? extends Message, ? extends TaskForm>> {

    public static <M extends TaskMapper<? extends Message, ? extends Message, ? extends TaskForm>> MapperFactory<M> getMapperFactory(Message msgIn, Message msgOut) {

        if (msgIn.isMyMapper())
            return new MyTaskMapperFactory();

        throw new IllegalStateException("Mapper not found!");
    }

    public abstract TaskMapper<? extends Message, ? extends Message, ? extends TaskForm> getTaskMapper();

    public static class MyTaskMapperFactory extends MapperFactory<MyTaskMapper> {

        @Override
        public TaskMapper<? extends Message, ? extends Message, ? extends TaskForm> getTaskMapper() {
            return new MyTaskMapper();
        }

    }
}

public interface TaskMapper<I extends Message, O extends Message, F extends TaskForm> {

    public F fillForm(I msgIn, O msgOut, F taskForm);

    public O fillMsgOut(F taskForm);
}

public class MyTaskMapper implements TaskMapper<IncomingMessage, OutgoingMessage, MyTaskForm > {

    public MyTaskForm fillForm(IncomingMessage msgIn, OutgoingMessage msgOut,
            MyTaskForm taskForm) {
        return null;
    }

    public OutgoingMessage fillMsgOut(MyTaskForm taskForm) {
        return null;
    }

}

Проблема в ошибке компиляции:

Несоответствие типов: невозможно преобразовать из MapperFactory.MyTaskMapperFactory to MapperFactory

в моем MapperFactory здесь:

if (msgIn.isMyMapper())
            return new MyTaskMapperFactory();

Есть идеи, как исправить эту ошибку?

Конечно, замена:

public static <M extends TaskMapper<? extends Message, ? extends Message, ? extends TaskForm>> MapperFactory<M> getMapperFactory(Message msgIn, Message msgOut) {

        if (msgIn.isMyMapper())
            return new MyTaskMapperFactory();

        throw new IllegalStateException("Mapper not found!");
    }

с:

public static MapperFactory<?> getMapperFactory(Message msgIn, Message msgOut) {

        if (msgIn.isMyMapper())
            return new MyTaskMapperFactory();

        throw new IllegalStateException("Mapper not found!");
    }

будет работать, но это не тот ответ, который я ищу.

Это, похоже, проблема с общим шаблоном абстрактной фабрики в целом. Также приветствуются ответы с исходными образцами с использованием пользовательских объектов.

Ответы [ 3 ]

4 голосов
/ 13 февраля 2012

Согласно Effective Java, 2-е издание, пункт 28:

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

Ваш метод getMapperFactory использует только параметр типа M в возвращаемом типе. Следуя этому совету, выдает следующую сигнатуру метода, и метод компилируется:

public static MapperFactory<? extends TaskMapper<Message, ? extends Message, ? extends String>> getMapperFactory(Message msgIn, Message msgOut)

РЕДАКТИРОВАТЬ: Чем больше я смотрю на код, тем больше я думаю, что MapperFactory не должен быть параметризован. Параметр здесь не используется, код getTaskMapper возвращает TaskMapper.

1 голос
/ 14 февраля 2012

Моим решением было бы уничтожение как можно большего количества генериков с помощью огня:

abstract class MapperFactory<M extends TaskMapper<?, ?, ?>> {

    public static MapperFactory<?> getMapperFactory(Message msgIn, Message msgOut) {
        if (msgIn.isMyMapper()) return new MyTaskMapperFactory();
        throw new IllegalStateException("Mapper not found!");
    }

    public abstract M getTaskMapper();
}


class MyTaskMapperFactory extends MapperFactory<MyTaskMapper> {

    @Override
    public MyTaskMapper getTaskMapper() {
        return new MyTaskMapper();
    }

}


interface TaskMapper<I extends Message, O extends Message, F extends TaskForm> {

    public F fillForm(I msgIn, O msgOut, F taskForm); 

    public O fillMsgOut(F taskForm);

}

class MyTaskMapper implements TaskMapper<IncomingMessage, OutgoingMessage, MyTaskForm> {

    public MyTaskForm fillForm(IncomingMessage msgIn, OutgoingMessage msgOut, MyTaskForm taskForm) {
        return null;
    }

    public OutgoingMessage fillMsgOut(MyTaskForm taskForm) {
        return null;
    }

}

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

1 голос
/ 08 февраля 2012

Оператор возврата отлично работает с типом:

return (BpmMapperFactory<MAPPER>)new Bpm007PrepareDocTaskMapperFactory();

Этот код никогда не будет выполнен, хотя в его текущей форме, потому что Bpm007PrepareDocTaskMapper не расширяет BpmCommonMessageDto, поэтому msgIn не может быть экземпляром Bpm007PrepareDocTaskMapper.

...