Может ли Guice создать фабрику для меня? - PullRequest
1 голос
/ 29 марта 2012

У меня есть следующий заводской класс:

public class MessagePresenterCreator implements IPresenterFactory{
    @Override
    public MessagePresenter createPresenter(Message m) {
        if (m instanceof Letter) {
            return new LetterPresenter();
        }
        if (m instanceof Cable) {
            return new CablePresenter();
        }
        if (m instanceof Postcard) {
            return new PostcardPresenter();
        }
        throw new IllegalArgumentException();
    }
}

Могу ли я настроить подсказку для автоматической генерации и поставки такой фабрики по следующему интерфейсу:

public interface IPresenterFactory {
    public abstract MessagePresenter createPresenter(Message m);
}

Ответы [ 2 ]

4 голосов
/ 29 марта 2012

Мне нравится думать о фабриках двумя способами: фабрики, которые просто собирают объекты из компонентов, и фабрики, которые делают условную логику в этой сборке.

За вашими фабриками стоит логика.Guice не может автоматизировать эту логику, потому что он просто обрабатывает зависимости.Если у вас есть созданный тип, которому требуется некоторое количество внедренных зависимостей и некоторые вещи, которые предоставляются только во время создания, тогда автоматическое подключение фабрик может быть выполнено с расширением AssistedInject guice .Это позволит вам предоставить интерфейс фабрики, аннотировать любые поля в созданном типе с помощью @AssistedInject, а расширение guice создаст класс реализации фабрики, который будет внедрять все, что связано в Injector, а также проходить через эти параметры create ().Но в таком случае все, что делают Guice и AssistedInject - это собирать кусочки вместе - связывать вещи по заранее заданному рецепту.Он не принимает решения о них в последнюю минуту.

Вы предоставляете условное создание объектов.Это не сработает.

Идея выше упоминает создание фабрики, которая зависит от отображения типа на презентатор - что-то вроде:

Map<Class<? extends Message>, Class<? extends MessagePresenter>> 

Это хороший подход, если вы объедините егос MultiBinder MapBindings .(Я должен расширить эти документы ... хм)

При таком подходе вы можете создать расширяемую фабрику - определяющую начальные отображения подклассов Message -> MessagePresenter, но оставьте возможность открытой для дополнительных сопоставлений позже, не имеячтобы изменить свою фабрику - просто привяжите больше сопоставлений к мультибиндеру, например так:

 MapBinder<String, Snack> mapbinder = MapBinder.newMapBinder(
     binder(), 
     new TypeLiteral<Class<? extends Message>>(){}, 
     new TypeLiteral<Class<? extends MessagePresenter>>(){});
 mapbinder.addBinding(MyMessage.class).toInstance(MyMessagePresenter.class);
 mapbinder.addBinding(YourMessage.class).toInstance(YourMessagePresenter.class);

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

1 голос
/ 29 марта 2012

Ни в одной манере нет встроенной фабрики. Вы могли бы написать фабрику, которая взяла Map<Class<? extends Message>, Class<? extends MessagePresenter> и использовала бы отражение.Таким образом, вы можете управлять им в модуле guice, если это ваша цель.

public class MessagePresenterCreator implements IPresenterFactory{
    private final Map<Class<? extends Message>, Class<? extends MessagePresenter> mapping;
    public MessagePresenterCreator(Map<Class<? extends Message>, Class<? extends MessagePresenter> mapping) {
         this.mapping = mapping;
    }

    @Override
    public MessagePresenter createPresenter(Message m) {
       Class<? extends MessagePresenter> clazz = mapping.get(m);
       if (clazz == null) {
           throw new UnsupportedOperationException();
       }
       return clazz.newInstance();
    }
}
...