如何将Guice Assisted Inject用于此工厂模式?

时间:2019-05-07 18:15:39

标签: java guice

以下是我编写的工厂模式。但是,为了将其更改为提供程序,Guice documentation并没有帮助。

class ClientA extends AbstractClient {...}
class ClientB extends AbstractClient {...}
class ClientUtil {
        private static AbstractClient client;
        public static AbstractClient getClient(String key) {
            ClientType clientType = ....
            switch(clientType) {
                case ".." : client = new ClientA.Builder()....build();
                            break;
                case "..." :
                default : client= new ClientB.Builder()....build();
            }
            return client;
        }
}
class Application {
        AbstractClient client = ClientUtil.getClient(key);  // here, key is a string which is dynamic
    }

请提供一些有关如何使用Guice AssistedInject以提供者格式编写的建议。

3 个答案:

答案 0 :(得分:1)

您是否尝试过手动编写Factory?您链接的手册中有一个很好的例子,您的代码可以轻松转换为Guice。

public interface ClientFactory {
    AbstractClient create(String key);
}

public class ClientFactoryImpl implements ClientFactory {
    @Override
    public AbstractClient create(String key) {
        if ("A".equals(key)) {
            return new ClientA();
        } else {
            return new ClientB();
        }
    }
}

并将工厂绑定到实现

bind(ClientFactory.class).to(ClientFactoryImpl.class);

AssistedInject对您的情况有害。它提供的所有功能都是自动构建ClientFactoryImpl。该实现仅将注入和辅助参数传递给构造函数。但是在create方法中您有一些平凡的逻辑。在这种情况下,建议您自己创建工厂实现。

答案 1 :(得分:1)

首先,我肯定会同意@Lesiak。代码"strain A25" 不清楚,因为省略号可以是您在ClientA / B上设置的任意多个字段。

但是要给您一个示例,说明如何对您的特定实例使用AssistedInject:

client= new ClientB.Builder()....build();

您的工厂将如下所示:

class ClientA extends AbstractClient {
    @Inject
    public ClientA(ServiceOne serviceOne,
            ServiceTwo serviceTwo,
            @Assisted MyObject myObject) {
        ...
    }
}

class ClientB extends AbstractClient {
    // Same constructor as ClientA
}

您的参数可以是不同的对象,也可以是您想要的任何对象,但是它们实际上必须与构造函数@Assisted注释匹配。现在您可以看到@Lesiak为何提供他的答案,如果您的构建器在ClientA上设置了10个字段,那么您的工厂方法将需要具有10个方法参数,并且非常不灵活。

然后将其用于:

interface ClientFactory {
    @Named("ClientA") public AbstractClient getClientA(...);
    @Named("ClientB") public AbstractClient getClientB(...);
} 

答案 2 :(得分:0)

假设您要直接创建对象,因此需要使用@Assisted,可以让Guice创建命名工厂:

import javax.inject.Inject;

// com.google.inject:guice:4.2.2
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.name.Names;
// com.google.inject.extensions:guice-assistedinject:4.2.2
import com.google.inject.assistedinject.Assisted;
import com.google.inject.assistedinject.FactoryModuleBuilder;

public class StackOverflow {
    public static void main(String[] args) {
        final Injector injector = Guice.createInjector(new GuiceModule());
        Key<ClientFactory> key = Key.get(ClientFactory.class, Names.named(args[0]));
        System.out.println("Client: " +  injector.getInstance(key).create("xxx"));
    }
}

class GuiceModule extends AbstractModule {
    @Override
    protected void configure() {
        install(new FactoryModuleBuilder().implement(AbstractClient.class, ClientA.class)
            .build(Key.get(ClientFactory.class, Names.named("ClientA"))));
        install(new FactoryModuleBuilder().implement(AbstractClient.class, ClientB.class)
            .build(Key.get(ClientFactory.class, Names.named("ClientB"))));
    }
}

abstract class AbstractClient {
}

class ClientA extends AbstractClient {
    private String key;
    @Inject
    public ClientA(@Assisted String key) {
        this.key = key;
    }
    @Override
    public String toString() {
        return "ClientA [key=" + key + "]";
    }
}

class ClientB extends AbstractClient {
    private String key;
    private Injector injector; // just an example for additional injections
    @Inject
    public ClientB(@Assisted String key, Injector injector) {
        this.key = key;
        this.injector = injector;
    }
    @Override
    public String toString() {
        return "ClientB [key=" + key + "]";
    }
}

interface ClientFactory {
    AbstractClient create(String key);
}

这种方法的缺点是,为了使用动态输入,您需要引用Injector,Guice抱怨这很慢-对于您而言,这可能不是问题。如果有人知道如何用更好的方法代替Directjector.getInstance调用,请告诉我!