是否可以优雅地提供Guice辅助注入工厂的实例,这些工厂不包含任何参数或等价物?

时间:2014-05-10 13:52:19

标签: java guice-3

好的,以下代码失败了。但是,如果有多个潜在的View实例,那么在您想要使用它们的地方注入大量的Provider提供程序会让人觉得笨拙。在我的情况下,这可能是可行的,但是我可以想象,在其他情况下,这并不是很好......所以我想我会问这个问题,而这在我脑海里是新鲜的。我还没有尝试过的一个解决方案是在方法中添加虚拟的@Assisted参数,并调用像factory.getView1(null),虽然这也不是很好。

注意,我可以看到为什么对于guice实现者来说这将是一个极端情况,因为guice必须知道不要调用构造函数(看起来像),而是使用提供者(它在技术上知道) 。不过,最好还是问一个解决方案,而不是假设没有解决方案。 : - )

import com.google.inject.*;
import com.google.inject.assistedinject.Assisted;
import com.google.inject.assistedinject.FactoryModuleBuilder;
import junit.framework.Assert;
import org.junit.Test;


public class GuiceTests {

    static class View1 implements Presenter.View {
        String name = null;
        @Override
        public String getName() { return null; }
        public void setName(String name) { this.name = name ;}
    }
    static class View2 extends View1 {}
    static class Presenter {
        interface View {public String getName();}
        @Inject
        public Presenter(@Assisted View view //, and other injected services
        ){}
    }

    interface Factory{
        Presenter getPresenter(Presenter.View view);
        View1 getView1();
        View2 getView2();
    }

    static class Module extends AbstractModule
    {
        @Provides View1 getView1()
        {
            View1 view1 = new View1(); //or possibly get this from an xml generator
            view1.setName("buddy");
            return view1;
        }

        @Override
        protected void configure() {

            install(new FactoryModuleBuilder().implement(Presenter.class, Presenter.class)
                    .build(Factory.class));
        }
    }

    /**
     * We're testing the ability here for assisted injected factories
     * to be used to produce entities provided by the module with NO
     * assisted arguments. This way they can conveniently be used in
     * conjuction with other factory assisted methods as shown below.
     * This fails!
     */
    @Test
    public void testAssisted()
    {
        Injector injector = Guice.createInjector(new Module());

        Factory factory = injector.getInstance(Factory.class);
        View1 view1 = factory.getView1();
        Assert.assertEquals("buddy", view1.getName());
        Presenter presenter = factory.getPresenter(view1);

    }
}

额外背景

Alan在下面问道:“你能举例说明使用它的真实代码(不叫注入器)会是什么样子吗?我不明白为什么你不会一起注入工厂和相关视图(或者为每个演示者的风格定义一个带注释的提供方法,即“

所以我有一个演示者可视化为有点浮动布局的卡片。此演示者具有某些业务逻辑,可使用一组服务配置自身。应用程序中有一个“新建”按钮,它为您提供了一张卡片视图,可以让您了解新过程(卡片上的配置)。一旦构建了卡,就会有一个不同的视图来表示卡...但它共享大部分相同的业务逻辑......所以理想情况下我想重用已经配置了模型的演示者..但现在附加建成的视图。使用内置视图重新创建持久卡片。 除非您正在进行讨论,否则请不要阅读。

注意上面的代码提炼了我充分的问题。下面的内容复杂化,因为它提供了更全面的背景。

//----------------

//on Add new entity
cardLayout.add(factory.getPresenterWithWizardView());

//-----------
//then later in the finish of the wizard
thePresenter.setView(factory.getConstructedView());
//I would prefer not to create a new presenter here, as the presenter also has layout
//state and logic that maintains and interacts with cardLayout to . Allowing for removing
//and adding a different presenter would trigger stuff affecting the state.

//--------------
//however elsewhere cards are loaded with 
cardLayout.add(factory.getPresenterWithBuiltView(cardFromDb));

2 个答案:

答案 0 :(得分:0)

所以我想除了直接使用大量的Providers(在需要的地方注入它们)之外,另一种方法是创建一个SanerFactory类,它具有像factory.getPresenterWithView1()这样的方法。这将是我可能必须注入多个提供商的唯一地方,孤立使用View1& View2直接实现。遗憾的是,还有更多的锅炉板需要维护。

答案 1 :(得分:0)

如果您知道有想要演示者的特定视图,我只想添加到您的模块中:

@Provides @Named("PresenterForView1")
public Presenter forView1(Factory factory, View1 view1) {
  return factory.getPresenter(view1);
}

(只有正确的注释而不是名称,并重复各种预制视图。)

如果您以后想要更改演示者的视图,我只需要注入该视图:

@Inject Constructor(@Named("PresenterForView1") Presenter presenter, View2 view2) {
  ...
  presenter.setView(view2);
  ...
}

(如果您不希望事先构建它,可能会注入Provider<View2>。)