- 代理模式的引入
- 代理模式的實例程序
- 代理模式的分析
代理模式的引入
Proxy是代理人的意思,指的是代替別人進(jìn)行工作的人器赞。當(dāng)不一定需要本人親自去做的工作的時候,就可以尋找代理人去完成。
但在代理模式中贝椿,往往是相反的敢会,通常是代理人碰到工作曾沈,就交給被代理的對象去完成,代理人只完成一些準(zhǔn)備工作或者收尾工作鸥昏。
如果讀者了解過spring框架的話塞俱,就會知道aop也就是面向切面編程其實運用的就是動態(tài)代理模式,這可以讓被代理的對象專注于完成自己的本職工作吏垮,而代理對象可以進(jìn)行工作前的日志記錄障涯,時間計算,在工作之后進(jìn)行日志記錄膳汪,收尾工作等附加的功能唯蝶,需要正式做工作的時候就交給被代理去做。就像插了兩個刀到這個被代理的對象前后遗嗽。所以形象的叫做面向切面編程粘我。
關(guān)于動態(tài)代理模式和靜態(tài)代理模式,感興趣的讀者可以參考筆者的另一篇博文:
Java動態(tài)代理與靜態(tài)代理http://www.reibang.com/p/b5e340ec9551
代理模式的實例程序
我們會實現(xiàn)一個打印機痹换,向屏幕打印一串字符串征字,然后交給代理對象去完成這個功能。
首先看一下類圖:
Printer類:
package Proxy;
public class Printer implements Printable {
private String name;
public Printer() {
heavyJob("正在生成Printer的實例");
}
public Printer(String name) { // 構(gòu)造函數(shù)
this.name = name;
heavyJob("正在生成Printer的實例(" + name + ")");
}
public void setPrinterName(String name) { // 設(shè)置名字
this.name = name;
}
public String getPrinterName() { // 獲取名字
return name;
}
public void print(String string) { // 顯示帶打印機名字的文字
System.out.println("=== " + name + " ===");
System.out.println(string);
}
private void heavyJob(String msg) { // 重活
System.out.print(msg);
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
System.out.print(".");
}
System.out.println("結(jié)束娇豫。");
}
}
Printable接口:
package Proxy;
public interface Printable {
public abstract void setPrinterName(String name);
public abstract String getPrinterName();
public abstract void print(String string);
}
PrinterProxy類,利用反射機制匙姜,動態(tài)生成被代理的對象,并且延遲初始化到需要調(diào)用它的時候再初始化
package Proxy;
public class PrinterProxy implements Printable {
private String name; // 名字
private Printable real; // “本人”
private String className; // “本人”的類名
public PrinterProxy(String name, String className) { // 構(gòu)造函數(shù)
this.name = name;
this.className = className;
}
public synchronized void setPrinterName(String name) { // 設(shè)置名字
if (real != null) {
real.setPrinterName(name); // 同時設(shè)置“本人”的名字
}
this.name = name;
}
public String getPrinterName() { // 獲取名字
return name;
}
public void print(String string) { // 顯示
realize();
real.print(string);
}
private synchronized void realize() { // 生成“本人”
if (real == null) {
try {
real = (Printable)Class.forName(className).newInstance();
real.setPrinterName(name);
} catch (ClassNotFoundException e) {
System.err.println("沒有找到 " + className + " 類冯痢。");
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
Main類測試:
package Proxy;
public class Main {
public static void main(String[] args) {
Printable p = new PrinterProxy("Alice", "Proxy.Printer");
System.out.println("現(xiàn)在的名字是" + p.getPrinterName() + "氮昧。");
p.setPrinterName("Bob");
System.out.println("現(xiàn)在的名字是" + p.getPrinterName() + "框杜。");
p.print("Hello, world.");
}
}
運行結(jié)果:
代理模式分析
代理模式中的角色:
Subject(主體)
Subject角色定義了使proxy和realsubject角色之間具有一致性的接口。這個接口提供了一個使用的好處郭计,就是client不必卻分它使用的是代理對象還是真實對象霸琴。
對應(yīng)實例中Printable角色Proxy(代理人)
Proxy角色會盡量處理來自Client角色的請求。只有當(dāng)自己不能處理的時候昭伸,就交給工作交給真實對象梧乘。代理對象只有在有必要時才會生成真實的對象。
實例中對應(yīng)的是PrinterProxy對象庐杨。RealSubject(真實對象)
就是實際完成工作的對象选调,對應(yīng)實例中的Printer對象。
代理模式的類圖:
用代理人來提升速度
關(guān)鍵就在于延遲初始化灵份。
我們可以等到需要使用到真實對象的功能才初始化仁堪。這樣的好處就是可以提升性能。從我們的實例中可能看不出這個優(yōu)勢填渠,假設(shè)我們有一個大型系統(tǒng)弦聂,如果我們都在系統(tǒng)啟動的時候,把所有功能初始化氛什,所有實例初始化莺葫,那么顯然系統(tǒng)的啟動將會變得很慢。但如果我們采用代理模式枪眉,那么就會在必須的時候捺檬,在初始化對象。這樣就加快了系統(tǒng)的啟動速度贸铜。代理和委托
其實我們學(xué)習(xí)了那么多設(shè)計模式堡纬,是不是感覺委托簡直無處不在。幾乎每個設(shè)計模式都會用到委托蒿秦,代理模式也不意外烤镐,就是代理了對象委托了真實對象。
因為委托可以是對象之間發(fā)生聯(lián)系渤早,互相調(diào)用湖雹。所以委托在很多設(shè)計模式中都存在躲叼。