题主,你好
看到你这个问题,我最开始联想到了Spring的控制反转,这很相似,就是实例有一个统一管理的地方,只是题主要求是根据参数不同来区分是否要创建新的实例,也就是说,实例创建决定于参数,那我们再更引申一点,不同的参数,若是不止不同于值,更不同在个数和类型上的话,那此时,实例创建决定于与参数和构造方法
所以下面的代码会把两个因素都考虑进去,结合我自己理解题主的意思,我总结了整个问题需要进入怎样的步骤最终创建一个实例出来,其实就是怎么写这个实例工厂
1. 提供创建实例的参数,这是输入
2. 根据实例的参数类型,找到匹配的构造函数
3. 先从缓存中,根据当前参数值+匹配的构造函数找当前是否已经存在了实例,若存在则直接返回实例
4. 若不存在,则用当前参数值+匹配的构造函数创建一个新实例,把相关数据放入缓存中,再返回新实例,这是输出
那现在我新增一个实例工厂类InstanceFactory,这个类中保存了某一个类的所有构造函数,也保存了该类所有的参数值+构造函数+实例的信息(这里有一个泛型,是方便最终你拿到的实例就是所要的实例,不用强转)
所以我要初始化某一个工厂时,我采用了这个init方法进行初始化,由于InstanceFactory初始化中对于参数值+构造函数是一个固定的数据,所以把这个工厂写成了静态变量放在了所需要创建实例的类VideoProcessorJNI中
public static final InstanceFactory instanceFactory = InstanceFactory.init(VideoProcessorJNI.class);
当然最终我会采取一个简单的public T get(Object … params)方法,来获取实例值,由于参数可变,所以get方法的参数也是可变的
VideoProcessorJNI videoProcessorJNI = VideoProcessorJNI.instanceFactory.get(“123”);
VideoProcessorJNI videoProcessorJNI1 = VideoProcessorJNI.instanceFactory.get(“xxxx”);
VideoProcessorJNI videoProcessorJNI2 = VideoProcessorJNI.instanceFactory.get(“123”);
现在我们就可以来填补刚才那几个方法了,首先是init方法,由于我们要保存参数类型+构造函数的关系,以及参数值+参数值+构造函数+实例的关系,所以会有两个map来存储关系
private Map constructorMap;
private Map> instanceMap = new HashMap<>();
所以init方法就简单了,我们只需要初始化constructorMap即可,并最终创建这个工厂返回
public static InstanceFactory init(Class targetClass){
Constructor[] declaredConstructors = targetClass.getDeclaredConstructors();
InstanceFactory factory = new InstanceFactory();
factory.constructorMap = Arrays.stream(declaredConstructors).collect(Collectors.toMap(InstanceFactory::toConstructorMapKey, Function.identity()));
return factory;
}
constructorMap的key其实就是当前参数类型的全名用’-‘拼起来的
private static String toConstructorMapKey(Constructor constructor){
Class[] parameterTypes = constructor.getParameterTypes();
String key = toConstructorMapKey(parameterTypes);
return key;
}
private static String toConstructorMapKey(Class … paramClassArray){
if (paramClassArray == null || paramClassArray.length == 0) return “”;
String key = Arrays.stream(paramClassArray).map(Class::getName).collect(Collectors.joining(“-“));
return key;
}
初始化了constructorMap,我们现在就可以来做get方法的处理了
public T get(Object … params){
String key = toConstructorMapKey(params);
Constructor constructor = constructorMap.get(key);
String instanceKey = toInstanceMapKey(params);
if (instanceMap.containsKey(instanceKey) && instanceMap.get(instanceKey).containsKey(constructor)){
return instanceMap.get(instanceKey).get(constructor);
}
try {
T t = constructor.newInstance(params);
this.putToInstanceMap(instanceKey, constructor, t);
return t;
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return null;
}
其实方法看起来也挺简单的,下面是InstanceFactory的完整代码
public class InstanceFactory {
private Map constructorMap;
private Map> instanceMap = new HashMap<>();
private InstanceFactory() {
}
public static InstanceFactory init(Class targetClass){
Constructor[] declaredConstructors = targetClass.getDeclaredConstructors();
InstanceFactory factory = new InstanceFactory();
factory.constructorMap = Arrays.stream(declaredConstructors).collect(Collectors.toMap(InstanceFactory::toConstructorMapKey, Function.identity()));
return factory;
}
public T get(Object … params){
String key = toConstructorMapKey(params);
Constructor constructor = constructorMap.get(key);
String instanceKey = toInstanceMapKey(params);
if (instanceMap.containsKey(instanceKey) && instanceMap.get(instanceKey).containsKey(constructor)){
return instanceMap.get(instanceKey).get(constructor);
}
try {
T t = constructor.newInstance(params);
this.putToInstanceMap(instanceKey, constructor, t);
return t;
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return null;
}
private void putToInstanceMap(String key, Constructor constructor, T t) {
Map constructorTMap = this.instanceMap.getOrDefault(key, new HashMap());
constructorTMap.put(constructor, t);
this.instanceMap.put(key, constructorTMap);
}
private String toInstanceMapKey(Object … paramArray) {
if (paramArray == null || paramArray.length == 0) return “”;
String key = Arrays.stream(paramArray).map(Object::toString).collect(Collectors.joining(“-“));
return key;
}
private static String toConstructorMapKey(Constructor constructor){
Class[] parameterTypes = constructor.getParameterTypes();
String key = toConstructorMapKey(parameterTypes);
return key;
}
private static String toConstructorMapKey(Class … paramClassArray){
if (paramClassArray == null || paramClassArray.length == 0) return “”;
String key = Arrays.stream(paramClassArray).map(Class::getName).collect(Collectors.joining(“-“));
return key;
}
private static String toConstructorMapKey(Object … paramArray){
if (paramArray == null || paramArray.length == 0) return “”;
Class[] paramClassArray = Arrays.stream(paramArray).map(Object::getClass).toArray(Class[]::new);
return toConstructorMapKey(paramClassArray);
}
}
下面可以来做一下测试
public class VideoProcessorJNI {
public static final InstanceFactory instanceFactory = InstanceFactory.init(VideoProcessorJNI.class);
private String param;
private Integer param1;
public VideoProcessorJNI(String param, Integer param1) {
this.param = param;
this.param1 = param1;
}
public VideoProcessorJNI(String param) {
this.param = param;
}
public static void main(String[] args) {
VideoProcessorJNI videoProcessorJNI = VideoProcessorJNI.instanceFactory.get(“123”);
VideoProcessorJNI videoProcessorJNI1 = VideoProcessorJNI.instanceFactory.get(“xxxx”);
VideoProcessorJNI videoProcessorJNI2 = VideoProcessorJNI.instanceFactory.get(“123”);
VideoProcessorJNI videoProcessorJNI3 = VideoProcessorJNI.instanceFactory.get(“123”, 1);
VideoProcessorJNI videoProcessorJNI4 = VideoProcessorJNI.instanceFactory.get(“123”, 2);
VideoProcessorJNI videoProcessorJNI5 = VideoProcessorJNI.instanceFactory.get(“123”, 1);
System.out.println(videoProcessorJNI);
System.out.println(videoProcessorJNI1);
System.out.println(videoProcessorJNI2);
System.out.println(videoProcessorJNI3);
System.out.println(videoProcessorJNI4);
System.out.println(videoProcessorJNI5);
}
}
运行结果
以上就是我个人的看法,仅供参考