命名,投掷对象的投掷提供者

时间:2016-05-04 03:44:46

标签: java guice

我现在已经随便使用guice了一段时间,但还不足以弄清楚如何在这种情况下完成我想要的东西。我似乎想要AssistedInjectThrowing ProvidersMultibindings的某种组合,但我不确定如何将它们整合在一起。这是一个没有完成工作的简化代码。它需要是Guicier!

public class Utilities {
    public static String expensiveLookup(String key) throws IOException {...}
}

public class Helper {
    @Inject private InjectedClass injectedValue;

    public Helper(String value1, String value2, String value3) {...}
}

public class Workhorse {

    // This map isn't very guicy. I'd prefer named bindings, or a multibinding
    private static Map<String, Helper> helpers = new HashMap();

    public static void register(String name, Helper helper) {
        helpers.put(name, helper);
    }

    ////////

    @Inject lots of things

    public void doHardWork(String helperName) {
        Helper helper = helpers.get(helperName);
        // do something hard
    }
}

class UserModule extends AbstractModule {
    protected void configure() {

        // Helpers are created with `new`, so they don't get `injectedValue`
        Workhorse.register("cheap helper", new Helper("cheap value", ...));

        try {
            // This expensive lookup should be delay until needed
            String expensiveValue = Utilities.expensiveLookup("expensive key");
            Workhorse.register("expensive helper", new Helper(expensiveValue, ...));
        } catch (IOException ex) {
            // This exception should be handled in `doHardwork()`
        }
    }
}

我可以弄清楚如何一次解决任何两个问题,但不是全部4:

  • Helper需要使用Guice创建,而不是new
  • expensiveLookup应该延迟到需要
  • IOException
  • 抓住并处理doHardWork
  • helpers映射应该可以用命名绑定或多绑定替换。这对我来说不是一个严格的要求,但似乎是正确的。

有人可以提供一些提示吗?

1 个答案:

答案 0 :(得分:0)

好吧,我终于找到了解决方案。我对它一定不满意,因为它需要大约两倍的代码并且难以理解,但它确实有效。我真诚地希望有一种更简单的方法。

public class Utilities {
    public static String expensiveLookup(String key) throws IOException {...}
}

public class Helper {
    private InjectedClass injectedValue;

    @Inject
    public Helper(
        @Assisted("value1") String value1, 
        @Assisted("value2") String value2, 
        @Assisted("value3") String value3,
        InjectedClass injectedValue) {

        this.injectedValue = injectedValue;
        ...
    }

    public static <T extends Provider> void installProvider(
        Binder binder, String name, Class<T> providerClass) {

        ThrowingProviderBinder.create(binder)
            .bind(ProviderInterface.class, Helper.class)
            .annotatedWith(Names.named(name))
            .to(providerClass)
            .in(Singleton.class);
    }

    abstract public static Provider implements ProviderInterface {
        @Inject private Factory factory;

        protected Helper expensiveBuild(
            String expensiveKey, 
            String value2, 
            String value3) throws IOException {

            String expensiveValue = Utilities.expensiveLookup(expensiveKey);
            return cheapBuild(expensiveValue, value2, value3);
        }

        protected Helper cheapBuild(String value1, String value2, String value3) {
            return Factory.create(value1, value2, value3);
        }
    }

    interface ProviderInterface extends CheckedProvider<Helper> {
        public Helper get() throws IOException;
    }

    interface Factory {
        Helper create(
            @Assisted("value1") String value1, 
            @Assisted("value2") String value2, 
            @Assisted("value3") String value3);
    }
}

class HelperModule exends AbstractModule {
    protected void configure() {
        install(new FactoryModuleBuilder()
            .implement(Helper.class, Helper.class)
            .build(Helper.Factory.class));
    }
}

public class Workhorse {
    @Inject lots of things
    @Inject private Injector injector;

    public void doHardWork(String helperName) {
        Key key = Key.get(Helper.ProviderInterface.class, Names.named(helperName));
        try {
            Helper helper = injector.getInstance(key).get(helperName);
            // do something hard
        } catch (IOException ex) {
            ...
        }
    }
}

class UserModule extends AbstractModule {
    protected void configure() {
        Helper.installProvider(binder(), "cheap helper", CheapProvider.class);
        Helper.installProvider(binder(), "expensive helper", ExpensiveProvider.class);
    }

    private static class CheapProvider extends Provider {
        public Helper get() {
            return cheapBuild("cheap value", ...);
        }
    }

    private static class ExpensiveProvider extends Provider {
        public Helper get() throws IOException {
            return expensiveBuild("expensive key", ...);
        }
    }
}

如果有人有更好的答案我会喜欢它!