設計模式——代理模式
模式介紹
代理模式:為其他物件提供一種代理以控制對這個物件的訪問。
代理模式(Proxy)是一種結構型設計模式,主要解決的問題是:在直接訪問物件時帶來的問題.
分類
靜態代理:代理類是在編譯時就實現好的。也就是說 Java 編譯完成後代理類是一個實際的 class 檔案。
動態代理:代理類是在執行時生成的。也就是說 Java 編譯完之後並沒有實際的 class 檔案,而是在執行時動態生成的類位元組碼,並載入到JVM中。
靜態代理模式結構
模式涉及角色
RealSubject 是原物件(或稱委託物件),ProxyObject是代理物件。
Subject 是委託物件和代理物件都共同實現的介面。
leave() 是委託物件和代理物件共同擁有的方法。
結構圖
(圖片來自網路,侵刪)
示例
比如某人要請假,因為有事不能直接去請假,可以找個同事(代理物件)幫他請假。
程式碼實現
/**
* ClassName: ProxyPattern <br/>
* Function: 靜態代理和動態代理<br/>
*
* @author gary.liu
* @date 2017/5/23
*/
public class ProxyPattern {
public static void main(String[] args){
/**
* 靜態代理測試
*/
RealSubject realSubject = new RealSubject(); //委託物件
ProxyObject proxyObject = new ProxyObject(realSubject); //代理物件
proxyObject.leave();
}
}
interface Subject{
/**
* 請假介面
*/
void leave();
}
class RealSubject implements Subject {
@Override
public void leave(){
System.out.println("RealSubject leave request");
}
}
class ProxyObject implements Subject {
private Subject subject;
public ProxyObject(Subject subject){
this.subject = subject;
}
@Override
public void leave(){
System.out.println("真正物件告訴代理幫他請假");
subject.leave();
System.out.println("代理告訴真正物件請假成功");
}
}
動態代理
動態代理的思維模式與之前的一般模式是一樣的,也是面向介面進行編碼,建立代理類將具體類隱藏解耦,不同之處在於代理類的建立時機不同,動態代理需要在執行時因需實時建立.
模式結構
和上面類似,需要一個介面和實現了這個介面的真實物件類,然後還要自己定義一個類(呼叫處理器類,即實現 InvocationHandler 介面),這個類的目的是指定執行時將生成的代理類需要完成的具體任務(包括Preprocess和Postprocess),即代理類呼叫任何方法都會經過這個呼叫處理器類。
結構圖
(圖片來自網路,侵刪)
程式碼實現
用動態代理實現上面的場景,需要自定義一個呼叫處理器類。
public class ProxyPattern {
public static void main(String[] args){
/**
* 動態代理測試
*/
ProxyHandler proxyHandler = new ProxyHandler(realSubject);
//動態生成代理物件
Subject proxySubject = (Subject) Proxy.newProxyInstance(RealSubject.class.getClassLoader(), RealSubject.class.getInterfaces(),
proxyHandler);
proxySubject.leave();
}
}
/**
* 動態代理實現上面的例子
*
*/
class ProxyHandler implements InvocationHandler {
private Subject subject;
public ProxyHandler(Subject subject){
this.subject = subject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args){
Object result = null;
System.out.println("真正物件告訴代理幫他請假");
try{
result = method.invoke(subject, args);
} catch (Exception e){
e.printStackTrace();
}
System.out.println("代理告訴真正物件請假成功");
return result;
}
}
jdk動態代理為什麼要求委託物件實現介面
//建立代理物件
static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
第二個引數是介面,表明這個代理類需要實現哪些介面。
因為 Java 的單繼承特性(每個代理類都繼承了 Proxy 類),只能針對介面建立代理類,不能針對類建立代理類。
手動生成的代理類寫入位元組陣列中
byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy1", RealSubject.class.getInterfaces());
然後寫入class檔案,用 jd-gui反編譯生產的代理類如下。
public final class $Proxy1 extends java.lang.reflect.Proxy implements com.lzhenxing.javascaffold.javabase.designpattern.Subject {
模式應用
代理模式用到的地方很多,比如 spring aop 使用的便是動態代理模式,spring aop 有兩種實現方式,一種是jdk動態代理(要求委託物件實現介面);另一種是位元組碼增強,委託物件可以不實現介面,具體實現如 cglib。
參考資料
《大話設計模式》
相關文章
- 設計模式-代理模式設計模式
- 設計模式----代理模式設計模式
- 設計模式~代理模式設計模式
- 【設計模式】代理模式設計模式
- js設計模式--代理模式JS設計模式
- Java設計模式—代理模式Java設計模式
- 設計模式之代理模式設計模式
- Java設計模式-代理模式Java設計模式
- 《設計模式》之代理模式設計模式
- PHP設計模式-代理模式PHP設計模式
- 設計模式 #5 (策略模式、代理模式)設計模式
- 代理設計模式設計模式
- Javascript設計模式之代理模式JavaScript設計模式
- Javascript設計模式(五)代理模式JavaScript設計模式
- JS設計模式四:代理模式JS設計模式
- Java 設計模式(四)《代理模式》Java設計模式
- Java設計模式之代理模式Java設計模式
- 設計模式學習——代理模式設計模式
- 設計模式 - 代理模式詳解設計模式
- 設計模式——代理模式的思考設計模式
- 軟體設計模式————(代理模式)設計模式
- 設計模式:代理模式詳解設計模式
- 極簡設計模式-代理模式設計模式
- 設計模式--介面卡模式/代理模式設計模式
- C++設計模式之Proxy模式(代理模式)C++設計模式
- 簡說設計模式——代理模式(續)設計模式
- 設計模式之代理模式(proxy pattern)設計模式
- 設計模式漫談之代理模式設計模式
- C++設計模式之代理模式C++設計模式
- Java設計模式之(五)——代理模式Java設計模式
- 搞懂設計模式——代理模式 + 原理分析設計模式
- 23種設計模式(四)-代理模式設計模式
- 23天設計模式之代理模式設計模式
- 設計模式之代理設計模式
- 23種設計模式之代理模式(靜態代理)設計模式
- 【設計模式】-代理模式及動態代理詳解設計模式
- 設計模式(七)Android中的代理模式設計模式Android
- 每天一個設計模式·代理模式設計模式