Java教程:Java設(shè)計(jì)模式之虛擬代理模式

字號:

虛擬代理模式(Virtual Proxy)是一種節(jié)省內(nèi)存的技術(shù),它建議創(chuàng)建那些占用大量內(nèi)存或處理復(fù)雜的對象時(shí),把創(chuàng)建這類對象推遲到使用它的時(shí)候。在特定的應(yīng)用中,不同部分的功能由不同的對象組成,應(yīng)用啟動(dòng)的時(shí)候,不會立即使用所有的對象。在這種情況下,虛擬代理模式建議推遲對象的創(chuàng)建直到應(yīng)用程序需要它為止。對象被應(yīng)用第一次引用時(shí)創(chuàng)建并且同一個(gè)實(shí)例可以被重用。這種方法優(yōu)缺點(diǎn)并存。
    優(yōu)點(diǎn):
    這種方法的優(yōu)點(diǎn)是,在應(yīng)用程序啟動(dòng)時(shí),由于不需要?jiǎng)?chuàng)建和裝載所有的對象,因此加速了應(yīng)用程序的啟動(dòng)。
    缺點(diǎn):
    因?yàn)椴荒鼙WC特定的應(yīng)用程序?qū)ο蟊粍?chuàng)建,在訪問這個(gè)對象的任何地方,都需要檢測確認(rèn)它不是空(null)。也就是,這種檢測的時(shí)間消耗是的缺點(diǎn)。
    應(yīng)用虛擬代理模式,需要設(shè)計(jì)一個(gè)與真實(shí)對象具有相同接口的單獨(dú)對象(指虛擬代理)。不同的客戶對象可以在創(chuàng)建和使用真實(shí)對象地方用相應(yīng)的虛擬對象來代替。虛擬對象把真實(shí)對象的引用作為它的實(shí)例變量維護(hù)。代理對象不要自動(dòng)創(chuàng)建真實(shí)對象,當(dāng)客戶需要真實(shí)對象的服務(wù)時(shí),調(diào)用虛擬代理對象上的方法,并且檢測真實(shí)對象是否被創(chuàng)建。
    如果真實(shí)對象已經(jīng)創(chuàng)建,代理把調(diào)用轉(zhuǎn)發(fā)給真實(shí)對象,如果真實(shí)對象沒有被創(chuàng)建:
    1) 代理對象創(chuàng)建真實(shí)對象
    2) 代理對象把這個(gè)對象分配給引用變量。
    3) 代理把調(diào)用轉(zhuǎn)發(fā)給真實(shí)對象
    按照這種安排,驗(yàn)證對象存在和轉(zhuǎn)發(fā)方法調(diào)用這些細(xì)節(jié)對于客戶是不可見的。客戶對象就像和真實(shí)對象一樣與代理對象進(jìn)行交互。因此客戶從檢測真實(shí)對象是否為null中解脫出來,另外,由于創(chuàng)建代理對象在時(shí)間和處理復(fù)雜度上要少于創(chuàng)建真實(shí)對象。因此,在應(yīng)用程序啟動(dòng)的時(shí)候,用代理對象代替真實(shí)對象初始化。
    例子:
    假設(shè)我們建立一個(gè)JAVA程序的集成開發(fā)環(huán)境(Integrated Development Environment),這個(gè)環(huán)境包括三個(gè)功能:編譯、運(yùn)行、生成JavaDoc文檔。在新建和編輯Java程序時(shí),最為常用的是編譯和運(yùn)行。至于生成JavaDoc文檔對于每一個(gè)Java程序不是必需的。因此,在Java開發(fā)環(huán)境啟動(dòng)時(shí),不要?jiǎng)?chuàng)建和裝載實(shí)現(xiàn)集成開發(fā)環(huán)境全部功能的所有對象,僅創(chuàng)建那些在編輯、編譯、運(yùn)行時(shí)用到的對象,保留提供生成JavaDoc文檔的對象,這是一個(gè)好的設(shè)計(jì)思想。這種對象創(chuàng)建策略能夠高效地利用內(nèi)存空間并且加快了集成開發(fā)環(huán)境的啟動(dòng)速度。
    假設(shè)編譯、運(yùn)行、生成JavaDoc文檔這些功能分別由三個(gè)工具類提供??Compiler、Runtime和JavaDoc。客戶對象可以訪問的不同IDE操作的接口以抽象類IDEOperation的形式定義。
    public abstract class IDEOperation {
    private Compiler cmp;
    private Runtime rtime;
    public void compile(String javaFile) {
    cmp.compile(javaFile);
    }
    public void run(String classFile) {
    rtime.run (classFile);
    }
    //to be delayed until needed.
    public abstract void generateDocs(String javaFile);
    public IDEOperation() {
    cmp = new Compiler();
    rtime = new Runtime();
    }
    }
    類IDEOperation提供了編譯、運(yùn)行java程序方法的實(shí)現(xiàn),作為它構(gòu)造函數(shù)的一部分,考試,大提示IDEOperation創(chuàng)建和裝載了進(jìn)行編譯和執(zhí)行操作的Compiler和Runtime對象。生成JavaDoc文檔的方法generateDocs方法被設(shè)計(jì)成抽象的方法,由它的子類來實(shí)現(xiàn)。
    讓我們定義抽象類IDEOperation的一個(gè)具體子類RealProcessor。作為RealProcessor構(gòu)造函數(shù)的一部分,創(chuàng)建JavaDoc對象來提供生成JavaDoc文檔的服務(wù),通過使用JavaDoc對象功能實(shí)現(xiàn)generateDocs方法。
    public class RealProcessor extends IDEOperation {
    JavaDoc jdoc;
    public RealProcessor() {
    super();
    jdoc = new JavaDoc();
    }
    public void generateDocs(String javaFile) {
    jdoc.generateDocs(javaFile);
    }
    }
    通過上面的實(shí)現(xiàn),RealProcessor類包含了編譯、運(yùn)行和生成JavaDoc文檔的所有功能。像我們原來討論的,生成JavaDoc文檔的功能不是每一個(gè)Java程序所必須的,當(dāng)RealProcessor實(shí)例化的時(shí)候,包括負(fù)責(zé)生成JavaDoc文檔的JavaDoc對象的一系列對象被創(chuàng)建。推遲創(chuàng)建JavaDoc對象有以下優(yōu)點(diǎn):
    1) 加速了RealProcessor對象的創(chuàng)建時(shí)間,因?yàn)樗臉?gòu)造函數(shù)創(chuàng)建的很少的對象。
    2) 高效地利用內(nèi)存,因?yàn)樵诓恍枰獙ο蠓?wù)的時(shí)候,不需要把對象保持在內(nèi)存中。
    在不改變RealProcessor實(shí)現(xiàn)的前提下,可以通過定義IDEOperation的另外一個(gè)子類ProxyProcessor來實(shí)現(xiàn)虛擬代理。因?yàn)镽ealProcessor和ProxyProcessor共享相同的接口,客戶對象可以用ProxyProcesso