1. 程式人生 > >Java設計模式之從[遊戲場景讀取]分析代理(Proxy)模式

Java設計模式之從[遊戲場景讀取]分析代理(Proxy)模式

  在大型遊戲中(如刺客信條、使命召喚等),我們需要讀取的地圖往往是很大的。如果我們在進入遊戲時,把所有的地圖資訊都讀出來,會花費很多的時間。那麼,為了提高效率,我們採取的措施是,我們並不需要真正把這些元素讀取出來,可以先用一些“不怎麼需要時間開銷的替代品”(也就是我們談到的代理)來代替這些需要花一定時間讀取的例項,等到我們真正需要這些例項的時候,再將這些“替代品”換成例項即可。例如,在一個射擊遊戲中,前面有個房子,這個房子我們未必會進去。那麼,在我們真正進入這個房子之前,這個房子內部是沒有必要例項化的,我們只要通過它的外觀判斷出它是一個房子即可,房子內部的東西,等我們進去再生成來提升效率。

  代理的意圖是為其他物件提供一種代理以控制這個物件的訪問。在上面的比方中,我們要建立一個代理,來控制生成房子的方法(即:只有即將進入房間內部,才需要生成房間內部的物件)。下面,我稍微將這個例子簡化了一下,請看Java程式碼:

interface House {
    void create() throws InterruptedException;
}

class LargeHouse implements House {
    public LargeHouse() throws InterruptedException{
        create();
    }
    public void create() throws InterruptedException{
        System.out.println("正在建立一個大房子……請等待2秒。");
        Thread.sleep(2000);
        System.out.println("房子建立完畢。");
    }
}

class LargeHouseProxy implements House {
    private LargeHouse largeHouse;
    public LargeHouseProxy(){   
    }
    public void create() throws InterruptedException{
        if (largeHouse == null) {
            largeHouse = new LargeHouse();
        }
    }
}

class Proxy
{
    public static void main(String[] args) throws InterruptedException {
        System.out.println("正在建立一個LargeHouse:");
        House largeHouse = new LargeHouse();
        System.out.println("正在建立一個LargeHouseProxy:");
        House largeHouseProxy = new LargeHouseProxy();
        System.out.println("LargeHouseProxy建立完畢!");
        largeHouseProxy.create();
    }
}

  我特意讓程式等待2秒,來模擬建立房子的時間開銷。下面簡要來分析一下上面一段程式碼。

  假設我們已經事先有了House介面和LargeHouse類,LargeHouse類在建立的時候就會自動呼叫create方法來建立一個房子,這並不是我們想要的,因為它會一次性花費很多時間來初始化,我們是想要它在我們需要的時候才建立房子。那麼,我馬上建立了一個LargeHouseProxy類,它是LargeHouse的代理。我們可以從程式碼上看出,我們建立LargeHouseProxy的時候並沒有馬上建立LargeHouse,而是呼叫create()的時候,才建立了一個LargeHouse,通過這種方式來控制對物件的建立和初始化。這樣做的好處之前也說過了,可以避免程式一次性將所有物件建立而造成巨大的開銷,這種代理方式也叫做“虛代理”。

  程式的執行結果如下:

正在建立一個LargeHouse:

正在建立一個大房子……請等待2秒。

房子建立完畢。

正在建立一個LargeHouseProxy:

LargeHouseProxy建立完畢!

正在建立一個大房子……請等待2秒。

房子建立完畢。

  代理的應用之一是智慧指標。如在C/C++語言中,沒有垃圾回收機制,我們可以為指標新增一個代理,讓它進行指標的計數,通過數量的統計來實現代理所管理的指標指向的記憶體能夠自動釋放來避免記憶體洩露等。

  乍一看代理模式和裝飾模式似乎挺像,因為它們均是為一個類中的方法來新增一些額外的行為,然而裝飾模式可以動態繼承來為方法提供額外行為,是為了遞迴組合而設計的(請見Java設計模式之再從[暗黑破壞神"裝備鑲嵌寶石系統"]分析裝飾(Decorator)模式),而代理模式的目的是,當直接訪問一個實體不方便或不符合需求時,為這個實體提供一個替代品。