以下是这种情况:我有一个带有构造函数的抽象类,它接受一个布尔值(它控制一些缓存行为):
abstract class BaseFoo { protected BaseFoo(boolean cache) {...} }
这些实现都是生成的源代码(很多都是)。我想自动为所有这些创建绑定,即不对每个被绑定的类型进行显式手动编码。我希望注入站点能够指定缓存或非缓存(true / false ctor param)。例如,我可能会进行两次注射:
DependsOnSomeFoos(@Inject @NonCaching AFoo aFoo, @Inject @Caching BFoo bFoo) {...}
(可以说这是一件坏事,因为决定是否缓存可能更好地在一个模块中。但考虑到我正在使用它,它似乎很有用。)
接下来的问题是 :配置绑定以统一方式生成 set 生成类型的最佳方法是什么,支持一个绑定注释以及具体类的构造函数参数?
以前我只在实现类上有一个默认构造函数,只需在每个生成的接口上放置一个@ImplementedBy。 E.g:
// This is all generated source...
@ImplementedBy(AFooImpl.class)
interface AFoo { ... }
class AFooImpl extends BaseFoo implements AFoo { AFooImpl() { super(true); } }
但是,现在我想允许各个注入点来判断是否将true或false传递给BaseFoo,而不是总是默认为true。我尝试设置一个注入监听器(偷偷摸摸)改变构造后的真/假值,但是我看不出如何“监听”用某个注释注入的类型的范围
我一直回到的问题是绑定需要针对特定类型,但我不想集中枚举所有类型。
我也考虑过:
我对这些想法都没有感觉很好。还有更好的方法吗?
更新:感谢您的评论和回答。我认为在每个类型旁边生成一个小模块并写出要在运行时通过getResources
提取的模块列表是赢家。
那就是说,在与一位同事交谈之后,我们可能会在提出问题时回避问题,而是在每个生成的类中使用类似boolean shouldCache(Class<? extends BaseFoo> c)
的方法注入一个策略对象。该策略可以在应用程序配置之上实现,并提供粗粒度和细粒度控制。这放弃了通过注射部位改变行为的要求。从好的方面来说,我们不需要额外的模块。
答案 0 :(得分:1)
除了你提到的内容之外,还有两种方法可供选择:
注入工厂类而不是真正的类;也就是说,你的手工编码的东西最终会说:
@Inject
DependsOnSomeFoos(AFoo.Factory aFooFactory, BFoo.Factory bFooFactory) {
AFoo aFoo = aFooFactory.caching();
BFoo bFoo = bFooFactory.nonCaching();
...
}
并且您生成的代码会说:
// In AFoo.java
interface AFoo {
@ImplementedBy(AFooImpl.Factory.class)
interface Factory extends FooFactory<AFoo> {}
// ...
}
// In AFooImpl.java
class AFooImpl extends BaseFoo implements AFoo {
AFooImpl(boolean caching, StuffNeededByAFIConstructor otherStuff) {
super(caching);
// use otherStuff
}
// ...
class Factory implements AFoo.Factory {
@Inject Provider<StuffNeededByAFIConstructor> provider;
public AFoo caching() {
return new AFooImpl(true, provider.get());
}
// ...
}
}
当然这取决于界面FooFactory:
interface FooFactory<T> {
T caching();
T nonCaching();
}
修改生成代码的过程,以生成随后在应用程序设置中使用的Guice模块。我不知道你的代码生成当前是如何构建的,但如果你有一些方法可以在代码生成时知道完整的类集,你可以直接执行此操作,也可以附加到某个文件,然后可以加载{{1作为Guice模块的一部分,它可以自动发现要绑定的类。