• [改善Java代码]枚举和注解结合使用威力更大


    注解的写法和接口很类似,都采用了关键字interface,而且都不能有实现代码,常量定义默认都是pulbic static final类型的.

    他们的主要不同点是:注解在interface前加上@字符,而且不能继承,不能实现,这经常会给我们的开发带来一些障碍.

    分析一个ACL(Access Contorl List ,访问控制列表)设计案例..看看如何避免这些障碍.

    ACL中有三个重要的元素:

    1.资源,有哪些信息是要被控制起来的.

    2.权限级别,不同的访问者在规划在不同的级别中.

    3.控制器(也叫鉴权人),控制不同的级别访问不同的资源.

    鉴权人是整个ACL的实际核心,我们从最主要的鉴权人开始,看代码:

    //鉴权者接口
    interface Identifier {
        //无权访问时的礼貌语
        String REFUSE_WORD = "您无权访问";
        // 鉴权
        public boolean identify();
    }

    这是一个鉴权人的接口,定义了一个常量和一个鉴权方法,接下来应该实现该鉴权方法,但问题是我们的权限级别和鉴权方法之间是紧耦合的,若分拆成两个类显得有点啰嗦,怎么办?我们可以直接定义一个枚举来实现.

    //常用鉴权者
    enum CommonIdentifier implements Identifier {
        //权限级别
        Reader, Author, Admin;
    
        //实现鉴权
        public boolean identify() {
            return false;
        }
    }

     定义了一个通用鉴权者,使用的是枚举类型,并且实现了鉴权者接口,现在就剩下资源定义了,这很容易定义,资源就是我们写的类,方法等,之后再通过配置来决定哪些类,方法允许什么级别的访问,这里的问题是:怎么把资源和权限级别关联起来呢?

    使用XML配置文件?是个方法,但是对于我们的示例程序来说显得太过繁重,使用注解会更简洁些.需要首先定义出权限级别的注解,代码如下:

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE)
    @interface Access {
        //确定什么级别可以访问
        CommonIdentifier level() default CommonIdentifier.Admin;
    }

     该注解是标注在类上面的,并且会保留到运行期,我们定义一个资源类,代码如下:

    //商业逻辑,默认访问权限是Admin
    @Access(level = CommonIdentifier.Author)
    class Foo {
    
    }

    Foo类只能是作者级别的人的访问,场景定义完毕,看如何模拟ACL的实现...看代码:

     1 import java.lang.annotation.ElementType;
     2 import java.lang.annotation.Retention;
     3 import java.lang.annotation.RetentionPolicy;
     4 import java.lang.annotation.Target;
     5 
     6 public class Client {
     7     public static void main(String[] args) {
     8         //初始化商业逻辑
     9         Foo b = new Foo();
    10         //获取注解
    11         Access access = b.getClass().getAnnotation(Access.class);
    12         //没有Access注解或者鉴权失败
    13         if (access == null || !access.level().identify()) {
    14             //没有Access注解或者鉴权失败
    15             System.out.println(access.level().REFUSE_WORD);
    16         }
    17 
    18     }
    19 
    20 }
    21 
    22 //商业逻辑,默认访问权限是Admin
    23 @Access(level = CommonIdentifier.Author)
    24 class Foo {
    25 
    26 }
    27 
    28 //鉴权者接口
    29 interface Identifier {
    30     //无权访问时的礼貌语
    31     String REFUSE_WORD = "您无权访问";
    32     // 鉴权
    33     public boolean identify();
    34 }
    35 
    36 //常用鉴权者
    37 enum CommonIdentifier implements Identifier {
    38     //权限级别
    39     Reader, Author, Admin;
    40 
    41     //实现鉴权
    42     public boolean identify() {
    43         return false;
    44     }
    45 }
    46 
    47 @Retention(RetentionPolicy.RUNTIME)
    48 @Target(ElementType.TYPE)
    49 @interface Access {
    50     //确定什么级别可以访问
    51     CommonIdentifier level() default CommonIdentifier.Admin;
    52 }

    打印输出:

    您无权访问

    这段代码,简单,易读,而且是通过ClassLoader类来解释该注解的,那会使开发更加简洁,所有的开发人员只要增加注解即可以解决访问控制问题.

    //======================================================================

     1 import java.lang.annotation.ElementType;
     2 import java.lang.annotation.Retention;
     3 import java.lang.annotation.RetentionPolicy;
     4 import java.lang.annotation.Target;
     5 
     6 public class Client {
     7     public static void main(String[] args) {
     8         MyAnno an1 = Foo.class.getAnnotation(MyAnno.class);
     9         MyAnno an2 = Impl.class.getAnnotation(MyAnno.class);
    10         System.out.println(an1);//@cn.summerchill.test.MyAnno(desc=@cn.summerchill.test.MyAnno2(a=a1a))
    11         System.out.println(an2);//@cn.summerchill.test.MyAnno(desc=@cn.summerchill.test.MyAnno2(a=aa))
    12         System.out.println(an1.hashCode());//391187329
    13         System.out.println(an2.hashCode());//391149008
    14         System.out.println(an1.equals(an2));//false
    15         System.out.println(an1 == an2);//false
    16     }
    17 }
    18 
    19 
    20 @MyAnno(desc =@MyAnno2(a="a1a"))
    21 class Foo {
    22     public void doSomething(){
    23         
    24     }
    25 }
    26 @MyAnno(desc =@MyAnno2(a="aa"))
    27 class Impl  {
    28     
    29     public void doSomething() {
    30     }
    31 }
    32 
    33 
    34 @Retention(RetentionPolicy.RUNTIME)
    35 @Target(ElementType.TYPE)
    36 @interface MyAnno {
    37     MyAnno2 desc();
    38 }
    39 
    40 @interface MyAnno2{
    41     String a() default "";
    42 }
  • 相关阅读:
    PHP
    优秀网址
    客户关系管理系统CRM
    面试题
    练习并熟练掌握交互式 SQL 语言
    嵌入式的SQL程序设计
    数据库总结
    JDBC
    玩转Android之Drawable的使用
    Android开发之Activity转场动画
  • 原文地址:https://www.cnblogs.com/DreamDrive/p/5640900.html
Copyright © 2020-2023  润新知