1. 程式人生 > >Java 靜態代理

Java 靜態代理

ram another some implement 而且 代理模式 from bce .com

Java 靜態代理

靜態代理通常用於對原有業務邏輯的擴充。比如持有二方包的某個類,並調用了其中的某些方法。然後出於某種原因,比如記錄日誌、打印方法執行時間,但是又不好將這些邏輯寫入二方包的方法裏。所以可以創建一個代理類實現和二方方法相同的方法,通過讓代理類持有真實對象,然後在原代碼中調用代理類方法,來達到添加我們需要業務邏輯的目的。

這其實也就是代理模式的一種實現,通過對真實對象的封裝,來實現擴展性。

一個典型的代理模式通常有三個角色,這裏稱之為**代理三要素**

package singleton;

public class TestProxy {
public static void main(String[] args) {
Subject subject = new ProxySubject();
subject.request();
}
}

抽象角色

abstract class Subject {
public abstract void request();
}

真實角色

class RealSubject extends Subject {
@Override
public void request() {
System.out.println("From real subject");
}

}

代理角色

class ProxySubject extends Subject {
private RealSubject realSubject;// 代理角色內部引用了真是角色

@Override
public void request() {
this.preRequest();// 在真實角色操作之前所附加的操作
if (null == realSubject) {
realSubject = new RealSubject();
}
realSubject.request();// 真實角色鎖完成的事情
this.postRequest();// 在真實角色操作之後所附加的操作
}

private void preRequest() {
System.out.println("pre request");
}

private void postRequest() {
System.out.println("post request");
}

}

運行結果:

pre request
From real subject
post request

也可以用接口表示抽象角色

共同接口

public interface Action {
    public void doSomething();
}

真實對象

public class RealObject implements Action{

    public void doSomething() {
        System.out.println("do something");
    }
}

代理對象

public class Proxy implements Action {
    private Action realObject;

    public Proxy(Action realObject) {
        this.realObject = realObject;
    }
    public void doSomething() {
        System.out.println("proxy do");
        realObject.doSomething();
    }
}

運行代碼

    Proxy proxy = new Proxy(new RealObject());
    proxy.doSomething();

技術分享圖片

這種代理模式也最為簡單,就是通過proxy持有realObject的引用,並進行一層封裝。

靜態代理的優點和缺點

先看看代理模式的優點: 擴展原功能,不侵入原代碼。

再看看這種代理模式的缺點:

假如有這樣一個需求,有十個不同的RealObject,同時我們要去代理的方法是不同的,比要代理方法:doSomething、doAnotherThing、doTwoAnotherThing,添加代理前,原代碼可能是這樣的:

realObject.doSomething();
realObject1.doAnotherThing();
realObject2.doTwoAnother();

為了解決這個問題,我們有方案一:

為這些方法創建不同的代理類,代理後的代碼是這樣的:

proxy.doSomething();
proxy1.doAnotherThing();
proxy2.doTwoAnother();

當然,也有方案二:

通過創建一個proxy,持有不同的realObject,實現Action1、Action2、Action3接口,來讓代碼變成這樣:

proxy.doSomething();
proxy.doAnotherThing();
proxy.doTwoAnother();

於是你的代理模型會變成這樣:

技術分享圖片

毫無疑問,僅僅為了擴展同樣的功能,在方案一種,我們會重復創建多個邏輯相同,僅僅RealObject引用不同的Proxy。

而在方案二中,會導致proxy的膨脹,而且這種膨脹往往是無意義的。此外,假如方法簽名是相同的,更需要在調用的時候引入額外的判斷邏輯。

package Test;

public class TestProxy {
public static void main(String[] args) {
Action1 action1 = new ProxySubject();
action1.requestFirstThing();
Action2 action2 = new ProxySubject();
action2.requestSecondThing();
Action3 action3 = new ProxySubject();
action3.requestThirdThing();

}
}

interface Action1 {
void requestFirstThing();
}

interface Action2 {
void requestSecondThing();
}

interface Action3 {
void requestThirdThing();
}

class RealSubject1 implements Action1 {
@Override
public void requestFirstThing() {
System.out.println("From real subject1");
}

}

class RealSubject2 implements Action2 {

@Override
public void requestSecondThing() {
System.out.println("From real subject2");
}
}

class RealSubject3 implements Action3 {

@Override
public void requestThirdThing() {
System.out.println("From real subject3");
}
}

class ProxySubject implements Action1, Action2, Action3 {
private RealSubject1 realSubject1;// 代理角色內部引用了真是角色
private RealSubject2 realSubject2;// 代理角色內部引用了真是角色
private RealSubject3 realSubject3;// 代理角色內部引用了真是角色

@Override
public void requestFirstThing() {
this.preRequest();// 在真實角色操作之前所附加的操作
if (null == realSubject1) {
realSubject1 = new RealSubject1();
}
realSubject1.requestFirstThing();// 真實角色鎖完成的事情
this.postRequest();// 在真實角色操作之後所附加的操作
}

private void preRequest() {
System.out.println("pre request");
}

private void postRequest() {
System.out.println("post request");
}

@Override
public void requestThirdThing() {
this.preRequest();// 在真實角色操作之前所附加的操作
if (null == realSubject2) {
realSubject2 = new RealSubject2();
}
realSubject2.requestSecondThing();// 真實角色鎖完成的事情
this.postRequest();// 在真實角色操作之後所附加的操作

}

@Override
public void requestSecondThing() {
this.preRequest();// 在真實角色操作之前所附加的操作
if (null == realSubject3) {
realSubject3 = new RealSubject3();
}
realSubject3.requestThirdThing();// 真實角色鎖完成的事情
this.postRequest();// 在真實角色操作之後所附加的操作
}
}

運行結果:

pre request
From real subject1
post request
pre request
From real subject3
post request
pre request
From real subject2
post request

Java 靜態代理