Java,多态,静态类型和"QueryInterface"模式

Jas*_*n S 5 java oop polymorphism api-design

我正在开发一个API设计,并且有一些关于Java和多态的东西,直到现在我都没想过.如果我创建这样的API:

interface FooFactory
{
    public Foo getFoo();
}

interface Foo
{
    public void sayFoo();
}
Run Code Online (Sandbox Code Playgroud)

那么我的FooFactory实现可以依赖的唯一的东西就是Foo实现.如果我决定提供一些增强的方法,像这样:

interface EnhancedFoo extends Foo
{
    public void patHeadAndRubBelly();
}

class EnhancedFooImpl implements EnhancedFoo
{
    ... implementation here ...
}

class EnhancedFooFactoryImpl implements FooFactory
{
    @Override public EnhancedFoo getFoo() { return new EnhancedFooImpl(); }
}
Run Code Online (Sandbox Code Playgroud)

我的API客户端可以使用该EnhancedFoo接口的唯一方法是,如果他们获得一个Foo接口并尝试将其转换为EnhancedFoo.

我记得Microsoft在IUnknown界面中处理COM的方式:

HRESULT QueryInterface(
   [in]   REFIID riid,
   [out]  void **ppvObject
);
Run Code Online (Sandbox Code Playgroud)

我们的想法是为你想要的接口传入一个GUID,如果成功,你会得到一个指针,保证你可以安全地将它转换为你想要的接口.

我可以用Java以类型安全的方式做类似的事情:

interface FooFactory
{
    public <T extends Foo> T getFoo(Class<T> fooClass);
}
Run Code Online (Sandbox Code Playgroud)

我在请求时提供一个实现,它返回所需子接口的实例,如果没有可用则返回null.

我的问题是:

  • QueryInterface模式是否合理?
  • 我应该只使用铸造吗?
  • 或者是处理API中的多态性以限制客户端严格使用相关普通方法的唯一正确方法?(例如Foo我的例子中的方法而不是任何EnhancedFoo方法)

澄清:客户端代码不会知道工厂实现.(假设它使用依赖注入或某些服务提供者体系结构,如java ServiceLoader或NetBeans Lookup.)因此,作为客户端,我不知道可用的是什么.工厂可能可以访问多个Foo衍生产品,我希望客户端能够请求它想要的功能集,并且要么得到它,要么它将不得不依赖于基本Foo功能.

我想对我来说困难的部分是这里存在运行时依赖性......纯静态类型安全方法,其中所有内容都在编译时修复,这意味着我只能依赖于该基本Foo功能.这种方法对我来说很熟悉,但后来我失去了可能的增强功能.虽然更动态/机会主义的方法可以利用这些功能,但我不确定构建使用它的系统的正确方法.

ass*_*ias 1

您可以简单地使用泛型声明您的工厂,并将其余部分保留原样:

static interface FooFactory {
  public <T extends Foo> T getFoo();
}
Run Code Online (Sandbox Code Playgroud)

然后由于类型推断,这将编译:

FooFactory f = new EnhancedFooFactoryImpl();
EnhancedFoo e = f.getFoo();
Run Code Online (Sandbox Code Playgroud)

(这在 Java 8 之前可能不起作用)

如果FooFactory不是您所期望的,该行将EnhancedFoo e = f.getFoo();抛出一个ClassCastException