對象關係行為模式之消極式載入

來源:互聯網
上載者:User
一、概念

Lazy Load:一個對象,它雖然不包含所需要的所有資料,但是知道怎麼擷取這些資料。

消極式載入貌似很簡單,就是在資料需要時再從資料庫擷取,減少資料庫的消耗。但這其中還是有不少技巧的。

二、實現消極式載入

實現Lazy Load主要有四種方法:延遲初始化、虛代理、值保持器和重影。

(1)延遲初始化(Lazy initialization)

1.1 概念

這個是最簡單的方法。意思就是每次訪問屬性域都要先檢查該域是否為空白,如果為空白,再擷取這個域的值。這樣必須做到所有對該域的訪問,即使來自類的內部,都要通過擷取方法來實現。

1.2 代碼實現

class Supplier{  private $products;  public function getProducts(){    if($products == null)      $products = $Product->findForSupplier();    return $products;  }}

1.3 使用時機

只有在域需要另外的資料庫訪問時才考慮使用消極式載入。

需要額外的調用,並且當使用主對象時所調用的資料沒有用到的時候。

最適用於活動記錄、表資料入口和行資料入口。

(2)虛代理(virtual proxy)

2.1 概念

實質為一對象,不包含任何東西,只有當它的一個方法被調用時,它才從資料庫載入恰當的對象。

說簡單點說是一個對象的代理對象,初始化時不載入對象,只有當代理對象被呼叫者法時才真正去載入。

2.2 代碼實現

/** * 虛代理,只有在被訪問成員時才調用閉包函數產生目標對象。 */class VirtualProxy{    private $holder = null;    private $loader = null;         /**     * @param Closure $loader 產生被代理對象的閉包函數     */    public function __construct(Closure $loader)    {        $this->loader = $loader;    }         /**     * 代理成員方法的調用     *      * @param string $method     * @param array  $arguments     * @throws BadMethodCallException     * @return mixed     */    public function __call($method, array $arguments = null)    {        $this->check();        if (!method_exists($this->holder, $method)) {            throw new BadMethodCallException();        }         return call_user_func_array(            array(&$this->holder, $method),             $arguments);    }         /**     * 代理成員屬性的讀取     *      * @param string $property     * @throws ErrorException     * @return mixed     */    public function __get($property)    {        $this->check();                 if (!isset($this->holder->$property)) {            throw new ErrorException();        }                 return $this->holder->$property;    }         /**     * 代理成員屬性的賦值     *      * @param string $property     * @param mixed  $value     */    public function __set($property, $value)    {        $this->check();                 $this->holder->$property = $value;    }         /**     * 檢查是否已經存在被代理對象,不存在則產生。     */    private function check()    {        if (null == $this->holder) {            $loader = $this->loader;            $this->holder = $loader();        }    }}// 測試$v = new VirtualProxy(function(){        echo 'Now, Loading', "\n";        $a = new ArrayObject(range(1,100));        $a->abc = 'a';        // 實際使用中,這裡調用的是 DataMapper 的 findXXX 方法        // 返回的是領域對象集合        return $a;});// 代理對象直接當作原對象訪問// 而此時構造方法傳入的 callback 函數才被調用// 從而實現載入對象操作的延遲echo $v->abc . $v->offsetGet(50);

(3)值保持器(value holder)

3.1 概念

一個用來封裝某個其他對象的對象,要想擷取基底物件,可以訪問值保持器得到它的值,但是只有第一次訪問值保持器時它真正從資料庫讀取資料。

(4)重影(ghost)

4.1 概念

部分狀態下的真實對象,當從資料庫載入對象的時候,它只包含其ID。當每次要訪問某個域時,它就會載入其完全狀態。把重影看成一個對象,它的每個域都是被一下子延遲初始化的,或者把它看成一個虛代理,對象本身就是它的虛代理。

4.2 代碼實現

//繼承要載入的對象class DeferredEventCollection extends EventCollection {    private $stmt;    private $valueArray;    private $run=false;//標識當前載入狀態        //構造方法,不真正擷取資料,只包含其$valueArray(ID)    function __construct( Mapper $mapper, \PDOStatement $stmt_handle,array $valueArray ) {        parent::__construct( null, $mapper );        $this->stmt = $stmt_handle;        $this->valueArray = $valueArray;    }        //載入完全狀態    function notifyAccess() {        if ( ! $this->run ) {            $this->stmt->execute( $this->valueArray );            $this->raw = $this->stmt->fetchAll();            $this->total = count( $this->raw );        }        $this->run=true;    }}

三、消極式載入的風險

1、繼承常常會給消極式載入帶來問題。如果要用重影,需要知道要建立什麼類型的重影,如果沒有正確載入資料,往往就很難說了。虛代理在待用資料類型語言中也會遇到同樣的問題。

2、消極式載入容易導致產生超出需要的資料庫訪問。書中別名“波動載入”。如用消極式載入來填充一個集合,然後每次只訪問其中一個元素。這樣就會每訪問一個對象就訪問一次資料庫,而不是一次把所需對象全部讀出來。這種載入方式會嚴重影響系統的效能。當然,可以不使用消極式載入的集合,而使類集合本身成為消極式載入,載入類集合時一次載入全部內容。

四、小結

消極式載入很適合於面向方面(AOP)的程式設計。可以將消極式載入操作置於一個單獨的方面,這樣能獨立改變消極式載入策略,領域開發人員也不必處理消極式載入的問題了。

無論你是否在領域類中顯式地添加消極式載入代碼,消極式載入都是一個好習慣。除了型別安全之外,使用集合對象而非數組的好處是你可以使用消極式載入。

  • 聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.