用注解的方式来解决不同子类的处理有关问题
用注解的方式来解决不同子类的处理问题
注解妙用~
最近在写一个同父类不同子类的处理方法,例如最简单的处理Number类的时候,假设返回值有不同类型,
如Long,Double,Integer等,并且需要对这些类型有不同的处理方式的时候,一般的情况下,我们可以使用下面这种方式来处理:
if( object instanceof Long){ //do long }else if(object instanceof Double){ //do double }else if(object instanceof Integer){ // do Integer }
简单的方式就可以区分不同子类类型的处理方式了。
不过这种方式很显然有个缺点,如果需要增加处理新的子类型的时候,需要修改到原有的判断逻辑,如加上
if( object instanceof Long){ //do long }else if(object instanceof Double){ //do double }else if(object instanceof Integer){ // do Integer }else if(object instanceof Float){ // do Float }
修改原有逻辑有风险,那么有没有其他方式可以既不修改原有的调用方式,同时可以满足处理新增子类型的需求呢?
我们可以试下用注解的方式,如下面代码
public class MethodInvokerDemo { /** * 测试类 * */ public static class A extends MethodInvoker { public void print(Number number, String userName) { String result = (String) invoke(number, userName); System.out.println(result); } @Invoke(classType = Double.class) protected String printDouble(Double obj, String userName) { return userName + " prints Double : " + obj; } @Invoke(classType = Long.class) protected String printLong(Long obj, String userName) { return userName + " prints Long : " + obj; } @Invoke(classType = Integer.class) protected String printInteger(Integer obj, String userName) { return userName + " prints Integer : " + obj; } } /** * 测试入口 * * @param args */ public static void main(String[] args) { A test = new A(); test.print(1.0, "lily"); test.print(323L, "kite"); test.print(5, "lucy"); } }
最后的结果如下:
lily prints Double : 1.0 kite prints Long : 323 lucy prints Integer : 5
我们可以看下具体是怎么实现的,下面是MethodInvoker的实现代码:
public class MethodInvoker { /** * 内部方法注解,标记方法和对应处理的类类型 * 使用方式:@Invoke( classType = Number.class) */ @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface Invoke { /** * 类类型 * * @return */ public Class<?> classType() default Object.class; } /** * 根据子类的注解调用对应的方法,如 invoke(new Long(1L)); * 则调用@Invoke(classType=Long.class)对应方法 * 参数类型和个数必须匹配 举例:<br> * * @param obj * @param parameters * @return */ protected final Object invoke(Object obj, Object... parameters) { if (obj == null) { return null; } this.refresh(); // 取出所有参数,拼装成参数数组 Object[] allParams = new Object[1 + (parameters == null ? 0 : parameters.length)]; if (parameters != null && parameters.length != 0) { for (int i = 1; i < allParams.length; i++) { allParams[i] = parameters[i - 1]; } } allParams[0] = obj; // 取出缓存的方法表 Method method = this.typeMethodMap.get(obj.getClass().getName()); if (method == null) { String className = obj.getClass().getSimpleName() + ".class"; throw new RuntimeException("can not find method for annotation @Invoke(classType=" + className + ")"); } // 设置调用权限为public try { method.setAccessible(true); } catch (Exception es) { // do nothing } // 调用该方法并返回结果 try { return method.invoke(this, allParams); } catch (Exception e) { String methodName = this.getClass().getName() + "." + method.getName(); throw new RuntimeException("execute " + methodName + " failed :" + e.getMessage(), e); } } /** * 刷新注解和方法的绑定关系 * */ private void refresh() { if (!typeMethodMap.isEmpty()) { return; } Map<String, Method> tmpMap = new ConcurrentHashMap<String, Method>(); Method[] methods = this.getClass().getDeclaredMethods(); if (methods != null && methods.length != 0) { for (Method method : methods) { Invoke invoke = method.getAnnotation(Invoke.class); if (invoke == null) { continue; } tmpMap.put(invoke.classType().getName(), method); } } typeMethodMap = tmpMap; } /** * 子类<注解对应的类名称,方法对象>缓存表 */ private Map<String, Method> typeMethodMap = new ConcurrentHashMap<String, Method>(); }
简单的继承MethodInvoker即可实现不同的子类使用不同的处理类型,并且不需要修改原有代码了,
如需要新增处理Float类型,我们只需要增加这个方法:
@Invoke(classType = Float.class) protected String printInteger(Float obj, String userName) { return userName + " prints Float: " + obj; }
1 楼
cevin15
2011-12-20