我正在从事API设计工作,而且到目前为止我还没有考虑过Java和多态的问题。如果我创建这样的API:
interface FooFactory
{
public Foo getFoo();
}
interface Foo
{
public void sayFoo();
}
然后我唯一能够依赖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(); }
}
并且我的API客户端可以使用EnhancedFoo
接口的唯一方法是,如果他们获得Foo
接口并尝试将其转换为EnhancedFoo
。
我记得Microsoft在IUnknown
界面中处理COM的方式:
HRESULT QueryInterface(
[in] REFIID riid,
[out] void **ppvObject
);
这个想法是你传入你想要的接口的GUID,如果成功,你会得到一个指针,保证你可以安全地将它转换到你想要的接口。
我可以使用Java以类型安全的方式做类似的事情:
interface FooFactory
{
public <T extends Foo> T getFoo(Class<T> fooClass);
}
我在请求时提供一个实现,它返回一个所需子接口的实例,如果没有可用的话,返回null。
我的问题是:
Foo
中的方法,而不是任何EnhancedFoo
方法) 澄清:工厂实施不会被客户端代码所知。 (让我们说它使用依赖注入或某些服务提供商架构,如java ServiceLoader
或NetBeans Lookup
。)所以作为客户,我不知道&# 39;可用。工厂可能有多个Foo
衍生产品的访问权限,我希望客户端能够请求它想要的功能集,并且要么得到它,要么它必须回退到基础{{1}功能。
我认为对我来说困难的部分是这里存在运行时依赖性...纯静态类型安全方法,其中所有内容都在编译时修复,这意味着我只能依赖于基本的Foo
功能。这种方法对我来说很熟悉,但后来我失去了可能的增强功能。虽然更动态/机会主义的方法可以利用这些功能,但我不确定构建使用它的系统的正确方法。
答案 0 :(得分:1)
您可以简单地使用泛型声明您的工厂,并按原样保留其余部分:
static interface FooFactory {
public <T extends Foo> T getFoo();
}
然后感谢类型推断,这将编译:
FooFactory f = new EnhancedFooFactoryImpl();
EnhancedFoo e = f.getFoo();
(这可能在Java 8之前不起作用)
如果FooFactory
不符合您的预期,则行EnhancedFoo e = f.getFoo();
会抛出ClassCastException
。
答案 1 :(得分:1)
为什么不参数化工厂界面?
static interface FooFactory<T extends Foo> {
public T getFoo();
}
然后:
class EnhancedFooFactoryImpl implements FooFactory<EnhancedFoo> {
@Override
public EnhancedFoo getFoo() { return new EnhancedFooImpl(); }
}
实例化:
FooFactory<EnhancedFoo> f1 = new EnhancedFooFactoryImpl();
EnhancedFoo foo = f1.getFoo();
当然,增强型工厂可用于需要基类的地方。
FooFactory<?> f2 = new EnhancedFooFactoryImpl();
Foo foo = f2.getFoo();
编辑(回复您的评论)
如果您的设计最好使用参数化工厂方法而不是工厂类,那么最好将其定义如下:
interface FooFactory {
public <T extends Foo> T getFoo(Class<T> fooClass);
}
这有两个方面的优势: 1.您可以控制用户想要创建哪些实际分类。 2.拥有一个类对象,你可以用反射来实例化它。
因此,在这种情况下,您不必使用特殊的Factory类来增强foo:
class FooFactoryImpl implements FooFactory {
@Override
public <T extends Foo> T getFoo(Class<T> c) {
try {
return c.newInstance();
} catch (ReflectiveOperationException e) {
return null;
}
}
}
然后用法如下:
FooFactory ff = new FooFactoryImpl();
EnhancedFoo ef = ff.getFoo(EnhancedFoo.class);
Foo f = ff.getFoo(Foo.class);
如果某些Foo实现需要构造函数参数,则可以始终在foctory方法中放置相应的if并“手动”实例化对象:
@Override
public <T extends Foo> T getFoo(Class<T> c) {
if(SomeParametrizedFoo.class.equals(c)) {
SomeParamtrizedFoo spf = new SomeParamtrizedFoo("constr arg");
spf.setParam(16136);
return (T) spf;
}
try {
return c.newInstance();
} catch (ReflectiveOperationException e) {
return null;
}
}