3

我正在开发一个“服务提供商”(非常类似于谷歌果汁)。它的工作是将任意 class_1 或接口映射到可以实例化的 *class_2*并实现 class_1(如果 class_1 是interface)或是/扩展 class_1(如果 class_1 不是接口)。

所以目前我有方法

public <T> void map(Class<T> key, Class<? extends T> service)

代码的问题是我可以将接口类型映射到接口类型

ServiceProvider sp = new ServiceProvider();
sp.map(IParent.class, IChild.class);

这完美地编译没有错误(IChild 扩展 IParent)。后来,当然,当我想:

IParent obj = sp.getService(IParent.class); //look for IParent mapping and instantiate the proper object

我收到 java.lang.InstantiationException。

所以问题是:

如何声明 map() 方法,以使编译器检查第二个参数是实现或扩展第一个参数的类而不是接口?(关键是得到编译时错误。我已经知道如何在运行时检查这个)

谢谢。PS:是的 - 谷歌搜索了很多,几乎没有发现。

UPD.: 谢谢大家的时间。也许再多说几句这一切:目标是开发机制(ServiceProvider 类),这将帮助我避免应用程序中的紧密耦合、硬依赖。所以我开发/采用了以下理念:“如果你想交付一个‘单元’(一块可重复使用的software) -- 声明所有公共接口;实施是你的私事,我们根本不关心;如果有人想使用你的单元,他们应该在 1 之前从 ServiceProvider 请求它。在启动时,他们使用 sp.map(IYuorInterface.class, TheClassImplementingIt.class); 2. IYuorInterface obj = sp.getService(IYuorInterface.class); 您有责任使 TheClassImplementingIt 类“可实例化”(构造函数、安全性、类不是抽象的等);如果不是 - 获得运行时异常是完全可以的。

有什么好处?

很明显——在任何给定时间,任何其他开发人员都可以使用 ServiceProvider 重新实现 IYuorInterface 映射它,然后所有应用程序都将使用它,而无需更改一行代码。(需要时最简单的情况——单元测试)

所以我的观点/问题是:map() 方法中的第二个参数必须是 Class 类型,它代表一个类,而不是接口,它应该与第一个参数“分配兼容”。

换句话说,当我做 map(ISomeIterface.class, Something.class); Something的对象(实例)应该可以像这样使用:

ISomeIterface obj = sp.getService(ISomeIterface.class);
//or in other words, just for example -- the Something can be used like this:
ISomeIterface obj = new Something();

这就是为什么工厂,正如一些答案所建议的那样是不可接受的,ServiceProvider 类已经是一种“工厂”


..似乎Java的Class对象代表类和接口,在编译时无法区分是真正的类还是接口..

但无论如何——谢谢大家。

4

3 回答 3

0

您可以使用

public boolean isConcrete(Class<?> input)
{
    if (input.isInterface())
         return false;

    if (Modifier.isAbstract(input.getModifiers()))
         return false;

    return true;
}
于 2013-04-17T09:30:50.227 回答
0

据我所知,如果Class对象表示可实例化的类,则无法在编译时检查。

即使在类的情况下,它也可能是抽象的,也可能缺少无参数构造函数。

作为替代方案,我建议您使用 Factory 对象而不是类本身。

于 2013-04-17T09:39:55.537 回答
0

如果您可以传递工厂而不是第二个参数,该怎么办。

interface IInterface{
    void go();
}

class IInterfaceImpl implements IInterface{
    public void go(){}
}

interface Factory<T>{
    T createInstance();
}

class FactoryImpl implements Factory<IInterface>{

    @Override
    public IInterface createInstance() {
        //you need to return an instance of IInterface, which can only be a class
        return new IInterfaceImpl();
    }
}
于 2013-04-17T09:48:46.250 回答