获取实现对象创建的几个接口的参数

时间:2011-02-27 19:57:21

标签: java interface implementation guice

我有一个对象,我想使用实现两个接口的对象创建(假设,我不能修改对象的类来创建将扩展两个接口的第三个接口)。使用guice创建此类对象的最佳方法是什么?

3 个答案:

答案 0 :(得分:4)

Java允许你进行接口组合,即

static class TL<T extends IA & IB> extends TypeLiteral<T>(){}

但你会发现确实必须有一个具体的类型T来实现这两个接口。 Java无法为变量创建“组合类型” - 类型必须与实际的类文件一起存在。

我很惊讶地发现确实有可能这样做。我怀疑这是一个黑暗的角落,Guice的维护者会建议不要进入,这可能不是一个好主意。

关于以下代码的注意事项:

  • 我实际上是滥用Guice的内置安全措施,方法是在IA上设置TL子类TypeLiteral而不是T上的TypeLiteral,这是正确的。事实上,这整个例子可能是偶然的。
  • 这没什么用。在这种情况下,某些东西最终必须指定具体类型(类Both)。它允许您在使用对象的类中指定具体类型,但不能在绑定它时或者直接从注入器请求它时
  • 几乎没有人理解TypeA&amp;带有Java泛型的TypeB语法 - 为任何看过这段代码的人做好准备,甚至是一些Java专家
  • 如果您稍后尝试使用仅实现一个接口的对象,则可以创建一个动态代理,该代理实现一个接口并委托给该对象,但是你仍然需要创建一个结合了两者的接口,为Java提供一个类型来引用

公共类X {

static final class TL<T extends IA & IB> extends TypeLiteral<IA> {}

interface IA {}
interface IB {}
static final class Both implements IA, IB {}

@Test
public void test() {
    Injector inj = Guice.createInjector(new M());
    Both object = inj.getInstance(Key.get(new TypeLiteral<Both>(){}));
    assertNotNull(object);
    Foo<Both> foo = inj.getInstance(Key.get(new TypeLiteral<Foo<Both>>() {}));
    assertTrue (object instanceof IA);
    assertTrue (object instanceof IB);
    assertNotNull(foo);
    assertNotNull(foo.obj);
}

static class Foo<T extends IA & IB> {
    private final T obj;
    @Inject
    Foo(T obj) {
        this.obj = obj;
    }
}

static class M extends AbstractModule {
    @Override
    protected void configure() {
        bind(new TL<Both>()).to(Both.class);
    }
}
}

所以我认为答案是,你可以,但你可能不应该。

答案 1 :(得分:3)

在需要时注入一个接口并转换为另一个接口,或者将相同的对象注入两个不同的接口两次。

我知道,两者都是丑陋的,但我认为整个方法都很难看。如果你需要两个不同的接口,一个类实现你可能在你的对象模型中有一个缺陷。如果一个类实现两个不相交的接口,它有两个不同的方面,你应该改进它cohesion

答案 2 :(得分:1)

为什么不这样做:

// Your original class
class AB implements IA, IB {...}

// In a Module
bind(AB.class).in(SOMESCOPE);
bind(IA.class).to(AB.class);
bind(IB.class).to(AB.class);

// In the object to be inejcted with AB
class MyClass {
    @Inject IA a;
    @Inject IB b;
}

最后,你实际上会有a == b,这不符合账单吗?