`
jak&jin
  • 浏览: 2611 次
  • 性别: Icon_minigender_1
  • 来自: 广州
最近访客 更多访客>>
文章分类
社区版块
存档分类
最新评论

用注解的方式来解决不同子类的处理问题

 
阅读更多

最近在写一个同父类不同子类的处理方法,例如最简单的处理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  
注解妙用~

相关推荐

    0006-自定义注解与设计模式.zip

    3. 处理注解:Java提供了反射API来读取注解信息。可以通过`AnnotatedElement`接口的`getAnnotation`方法获取注解实例,然后访问其元素。 其次,设计模式是面向对象设计中的一种最佳实践,是对常见问题的解决方案。...

    @TypeDiscriminator注解实现多态对象的查询,jackson @JsonTypeInfo注解实现controller多态支持

    `@TypeDiscriminator` 和 `@JsonTypeInfo` 这两个注解分别来自Spring和Jackson库,它们用于解决序列化和反序列化过程中多态对象的处理问题。 首先,`@TypeDiscriminator` 是Spring Data JPA提供的一种注解,用于在...

    BTrace二三事之二:OnMethod子类匹配BUG(怀疑)

    当使用`OnMethod`注解时,如果目标方法在父类中定义,BTrace可能无法正确地在子类的相应实例上调用该方法的探针。这个问题可能导致跟踪丢失或者错误的结果。 为了更深入地理解这个问题,我们需要查看BTrace的源码。...

    AOP-CGLIB学习-实现简单的注解权限系统

    自定义注解`Role`使用了`@Target`来指定它可以应用于方法、构造器和字段,`@Retention`设为`RUNTIME`,表示注解在运行时依然有效,`@Inherited`则表示子类可以继承这个注解。 权限检查的逻辑通常会通过Spring的AOP...

    sqlite 注解获取建表sql

    本篇文章将深入探讨如何通过注解的方式来获取SQLite中的建表SQL,并利用反射来将Cursor对象转换为Java Bean或列表。 首先,让我们了解如何使用注解来定义Java Bean的字段以生成对应的SQL建表语句。在Java中,注解是...

    全面解析java注解PPT课件.pptx

    此外,还可以使用元注解来修饰自定义注解,例如`@Retention`控制注解的生命周期,`@Target`指定注解可以应用于哪些程序元素,`@Documented`指示是否包含在Javadoc中,`@Inherited`让子类继承父类的注解。 在实际...

    Mybatis注解手写源码篇

    在执行SQL时,Executor会根据不同的注解调用相应的JDBC API,如`prepareStatement`、`executeQuery`等,来与数据库进行交互。 然后,我们来讨论结果处理。Mybatis支持两种结果处理方式:ResultMap和自动映射。...

    The method of type must override a superclass method解决方式, myeclipse, java, web

    在此,我们将深入探讨这个问题及其解决方式,同时也会涉及MyEclipse集成开发环境(IDE)中的相关操作。 首先,让我们了解Java中的方法重写。当一个子类需要扩展或修改父类的功能时,会覆盖父类的方法。重写的规定是...

    Struts 2 数据校验功能及校验问题的解决方案

    总的来说,Struts 2的数据校验机制是通过ActionSupport类及其扩展的接口来实现的,提供了多种方式来满足不同的校验需求。开发者可以根据项目需求选择适合的校验策略,确保输入数据的准确性和一致性,从而提高应用的...

    JPA框架新技术: 注解

    可以通过修改其他关联为 FetchType.LAZY 或者将 List 集合改为 Set 来解决此问题。** 3. **关于一对多关联的优化**,可以在一方使用延迟加载的方式减少数据库访问次数。例如,通过在HQL查询中使用“迫切左外连接”...

    AndroidInject增加sqlite3数据库映射注解(ORM).rar

    ORM允许开发者用面向对象的方式来处理数据库,而无需直接编写SQL语句,提高了代码的可读性和可维护性。 首先,AndroidInject是一个基于Dagger 2的依赖注入框架,它帮助我们管理应用程序中的对象生命周期和依赖关系...

    JPA注解参考

    JPA提供了一系列注解来处理实体之间的关联关系,如一对一、一对多、多对多等。 - **@OneToOne**、**@ManyToOne**、**@OneToMany**、**@ManyToMany**:分别表示一对一、一对多、多对一和多对多的关系。这些注解可以...

    java学习笔记(11) 第11 章 - 枚举和注解(csdn)————程序.pdf

    因此,引入枚举类可以更好地解决这个问题,确保枚举类型只能包含预定义的几个值。 11.2 问题解析 枚举类型的特点是: - 枚举值是有限的,如季节的四个值。 - 枚举对象通常是只读的,不允许修改。 11.3 自定义类...

    java中lombok的@Data引发问题详解

    一种解决方案是明确地在子类中添加`@EqualsAndHashCode(callSuper = true)`注解,以确保父类的字段也被考虑在内。另一种选择是放弃使用`@Data`,而是单独使用`@Getter`、`@Setter`、`@ToString`和`@...

    跨站点脚本编制问题解决

    同时,使用`HttpMessageConverter`的子类,如`MappingJackson2HttpMessageConverter`,可以通过配置`ObjectMapper`来实现JSON响应中的安全编码。 对于存储型XSS,我们需要在保存用户输入到数据库之前进行清理或编码...

    spring多个动态代理导致循环依赖报错问题解决

    2. **使用`@Lazy`注解**:在依赖注入的bean上添加`@Lazy`注解,可以延迟初始化,直到真正使用到该bean时才创建。这可以打破循环依赖,但要注意`@Lazy`与AOP的结合可能引发问题,需要谨慎使用。 3. **调整代理模式**...

    异常处理.pdf

    Java异常机制是Java语言的一种错误处理方式,它提供了一种标准的方法来处理程序运行时可能出现的错误。通过异常处理,我们可以将正常业务代码和异常处理代码分开,使程序的逻辑更清晰,增强程序的健壮性。 异常机制...

    详解Java编程中Annotation注解对象的使用方法

    在Java编程中,Annotation(注解)是一种...总之,Java的注解提供了一种强大而灵活的方式来添加元数据,从而改进代码的可读性、可维护性和可扩展性。通过自定义注解和处理器,开发者可以构建出适应特定需求的解决方案。

    JPA 实现继承关系

    在Java世界中,Java Persistence API (JPA) 是一种用于管理关系数据库的框架,它提供了对象-关系映射(ORM)的功能,使得开发者可以使用面向对象的方式来操作数据库。本篇文章将深入探讨如何在JPA中实现继承关系,这...

Global site tag (gtag.js) - Google Analytics