[改善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 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM