1. 程式人生 > >【java設計模式】之 代理(Proxy)模式

【java設計模式】之 代理(Proxy)模式

代理模式的核心作用就是通過代理,控制對物件的訪問。這跟實際中是一樣的,比如說明星都有經紀人,這就是一個代理,比如有人要找某明星拍戲,那麼首先處理這事的是他的經紀人,雖然拍戲需要自己拍,但是拍戲前後的一些必須要做的事等等,都由這個經紀人來處理。 
  在程式中也是如此,通過代理,可以詳細控制訪問某個或者某類物件的方法,在呼叫這個方法前做前置處理,呼叫這個方法後做後置處理。這也是AOP的實現原理。 
  那麼代理模式的核心角色該如何設計呢?

設計思路:定義一個抽象角色,讓代理角色和真實角色分別去實現它。 
1. 真實角色:實現抽象角色,定義真實角色所要實現的業務邏輯,供代理角色呼叫它只關注真正的業務邏輯

,比如拍戲。 
2. 代理角色:實現抽象角色,是真實角色的代理,通過真是角色的業務邏輯方法來實現抽象方法,並可以附加自己的操作,比如談合同,佈置場地等等。

  下面來具體實現這個代理模式,代理模式分為靜態代理和動態代理。靜態代理是我們自己建立一個代理類,而動態代理是程式自動幫我們生成一個代理,我們就不用管了。

1. 靜態代理

根據上面的實現步驟,首先來寫一個抽象角色:

/**
 * @Description 介面類
 * @author Ni Shengwu
 *
 */
public interface Star {

    public void confer(); //面談
    public
void sing(); //唱歌 public void collectMoney(); //收錢 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

這個抽象類中有三個方法,現在分別讓真實角色和代理角色來實現該抽象類:

/**
 * @Description 真實物件
 * @author Ni Shengwu
 *
 */
public class RealStar implements Star {

    @Override
    public void confer() {
        System.out.println("RealStar.confer()");
    }

    @Override
public void sing() { System.out.println("RealStar(周杰倫).sing()"); } @Override public void collectMoney() { System.out.println("RealStar.collectMoney()"); } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

唱歌部分,註明一下週杰倫,等會好區分。下面再來看下代理類。

/**
 * @Description 代理類
 * @author Ni Shengwu
 *
 */
public class ProxyStar implements Star {

    private Star star;

    public ProxyStar(Star star) { //到時候傳進來真實的star
        super();
        this.star = star;
    }

    @Override
    public void confer() {
        System.out.println("ProxyStar.confer()");
    }

    @Override
    public void sing() {
        //其他事都能幹,唯一不能幹的就是唱歌,唱歌還是得要周杰倫本人來唱
        star.sing(); //讓他本人來唱
    }

    @Override
    public void collectMoney() {
        System.out.println("ProxyStar.collectMoney()");
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

  在代理類中,可以看到,維護了一個Star物件,通過構造方法傳進來一個真實的Star物件給其賦值,然後在唱歌這個方法裡,使用真實物件來唱歌。所以說面談、收錢都是由代理物件來實現的,唱歌是代理物件讓真實物件來做。 
下面寫個客戶端的測試用例:

public class Client {

    public static void main(String[] args) {
        Star real = new RealStar();
        Star proxy = new ProxyStar(real);

        proxy.confer();
        proxy.sing();
        proxy.collectMoney();
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

輸出結果:

ProxyStar.confer() 
RealStar(周杰倫).sing() 
ProxyStar.collectMoney()

可以看出,客戶端只跟代理物件打交道,代理物件把能做的都做了,比如面談和收錢,唱歌呢,是呼叫真實物件去唱。

2. 動態代理

  動態代理比靜態代理使用的更廣泛,動態代理在本質上,代理類不用我們來管,我們完全交給工具去生成代理類。Star介面和RealStar實現類還是和上面的一樣,下面來定義一下代理類,使用動態代理需要實現InvocationHandler介面,並覆寫裡面的invoke方法,如下:

/**
 * @Description 動態代理類
 * @author Ni Shengwu
 *
 */
public class StarHandler implements InvocationHandler {

    Star realStar;

    public StarHandler(Star realStar) {
        super();
        this.realStar = realStar;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {

        Object object = null;

        // 在代理真實物件前,我們可以做些自己的操作
        System.out.println("面談");

        if(method.getName().equals("sing")) {
            object = method.invoke(realStar, args);
        }

        // 在代理真是物件後,我們可以做些自己的操作
        System.out.println("收錢");

        return object;
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

  可以看出,思路和靜態代理是一樣的,先通過構造方法把真正的物件傳進來,然後執行代理的部分是invoke方法中,在該方法中,我們進行一次判斷,只有當需要唱歌的時候,我就呼叫剛剛傳進來的真實物件來唱,其他事情由代理代替真實物件來做,這裡只用控制檯輸出來模擬一下。 
  最後來寫個客戶端測試一下:

public class Client {

    public static void main(String[] args) {

        Star realStar = new RealStar();
        StarHandler handler = new StarHandler(realStar);

        //建立代理類
        Star proxy = (Star) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{Star.class}, handler);       

        proxy.sing();
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

看下控制檯輸出:

面談 
RealStar(周杰倫).sing() 
收錢

  由此可見,使用代理可以在執行某個邏輯的前後加上新的邏輯,這是很好的功能,實際中spring的AOP用的就是這種技術。