Java的代理模式
代理模式:在原來物件的基礎上增加一個代理物件,通過代理對被代理物件進行訪問。代理不僅起到了中介的作用,還可以在原物件的基礎上增加或刪減一些功能。常用的代理可以分為以下四種:
- 遠端代理:為不同地址空間的物件在當前區域網內提供一個代表物件,例如通過代理管理多個地方的店鋪分店。
- 虛擬代理:根據需要將資源消耗很大的物件進行延遲建立,直到真正需要的時候再建立。例如圖片的懶載入
- 保護代理:控制物件的訪問許可權,只有特定許可權的使用者可以訪問物件。
- 智慧引用代理:對目標物件新增額外的服務
靜態代理
代理和被代理物件之間關係在編碼時確定,它們都實現了相同的介面或繼承自相同的抽象類。實現靜態代理有兩種方式:通過繼承的方式、通過聚合的方式。
如下所示為通過繼承的方式實現代理。首先定義一個實現了TicketInterface介面的被代理類TicketOffice用於實現售票的功能,接著為售票處定義一個代理類TicketProxy
,並在售票的基礎上增加搶票的功能。這樣便實現了一個最簡單靜態代理
//公共介面
public interface TicketInterface {
void saleTicket();
}
//被代理類
public class TicketOffice implement TicketInterface {
public void saleTicket(){
System.out. println("出售車票");
}
}
//定義代理類
public class TicketProxy extends TicketOffice {
public void saleTicket(){
System.out.println("進行搶票..."); //增加搶票的功能
super.saleTicket(); //呼叫被代理類原來的的方法
}
}
public static void main(String[] args) {
TicketProxy ticketProxy= new TicketProxy();
ticketProxy.saleTicket();
}
通過聚合的方式實現代理即在一個類中呼叫另一個類的方法從而實現代理。例如定義代理類TicketProxy2,在初始化時傳入被代理物件TicketOffice,並在類內部呼叫該物件的方法從而實現代理,並且在原售票功能的基礎上增加了退票功能。
public class TicketProxy2 {
private TicketOffice saler;
public TicketProxy2(TicketOffice saler) { //傳入被代理物件
super();
this.saler = saler;
}
public void saleTicket(){
saler.saleTicket(); //呼叫被代理物件的方法
System.out.println("進行退票...");
}
}
public static void main(String[] args) {
TicketOffice seller =new TicketOffice();
TicketProxy2 proxy2=new TicketProxy2(seller); //通過聚合的方式傳入物件進行代理
proxy2.saleTicket();
}
通過上面的兩種方式可以看出繼承的方式每增加一個代理方式都要新建立一個類,而聚合方式只需要通過物件傳遞不同的組合、順序即可,可見聚合的方式更為靈活。
動態代理
靜態代理只能針對一種被代理物件實現代理服務,如果是另一種類似的物件,則需要新建立代理。而動態代理則可以根據不同的類、不同的方法動態產生代理。如下所示,代理類ProxySubject
通過newProxyInstance()方法生成一個動態代理類Proxy。之後經過事務處理器ProxyHandler
,它實現了InvocationHandler介面的方法invoke()
,在其中呼叫被代理類的方法和實現一些自定義的代理操作。最後是被代理類RealSubject。
如下所示,首先定義事務處理器TicketHandler用於定義代理,可以傳入任何型別的被代理物件Object,然後在invoke()方法中進行代理操作–進行搶票,再呼叫被代理物件的方法。
在主函式main中使用動態代理,首先建立被代理物件ticketOffice,然後據此建立事務處理器handler。接著通過Proxy.newProxyInstance()
建立動態代理物件,它接收三個引數:被代理物件的類載入器、實現的介面與事務處理器。最後通過返回的返回動態代理物件,呼叫方法。
//事務處理器
public class TicketHandler implements InvocationHandler {
private Object target;
public TicketHandler(Object target) { //初始化時傳入被代理物件
this.target = target;
}
/**
* 實現介面的invoke方法
* @param proxy 被代理的物件
* @param method 被代理物件的方法
* @param args method 方法的引數列表
* @return method 方法的返回值
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("進行搶票..."); //增加自定義的操作
method.invoke(target); //呼叫被代理物件的方法
return null;
}
}
public static void main(String[] args) {
TicketOffice ticketOffice=new TicketOffice(); //1、建立被代理物件
InvocationHandler handler=new TicketHandler(ticketOffice); //2、建立事務處理器
ClassLoader loader=ticketOffice.getClass().getClassLoader(); //獲取被代理物件的類載入器
Class[] interfaces=ticketOffice.getClass().getInterfaces(); //被代理物件所實現的介面
//3、通過newProxyInstance()生成動態代理類物件
TicketInterface dynamicProxy=(TicketInterface)Proxy.newProxyInstance(loader,interfaces,handler);
dynamicProxy.saleTicket(); //4、通過動態代理物件呼叫方法
}