Heim  >  Artikel  >  Backend-Entwicklung  >  Objektrelationales Verhaltensmuster Lazy Loading

Objektrelationales Verhaltensmuster Lazy Loading

巴扎黑
巴扎黑Original
2016-11-12 10:19:04970Durchsuche

1. Konzept

Lazy Load: ein Objekt, das zwar nicht alle erforderlichen Daten enthält, aber weiß, wie es die Daten erhält.

Lazy Loading scheint sehr einfach zu sein. Es besteht darin, die Daten bei Bedarf aus der Datenbank abzurufen, um den Verbrauch der Datenbank zu reduzieren. Aber es sind immer noch viele Tricks dabei.

2. Lazy Loading implementieren

Es gibt vier Hauptmethoden zum Implementieren von Lazy Load: verzögerte Initialisierung, virtueller Proxy, Werthalter und Ghosting.

(1) Verzögerte Initialisierung (Lazy Initialization)

1.1 Konzept

Dies ist die einfachste Methode. Dies bedeutet, dass Sie bei jedem Zugriff auf ein Attributfeld zunächst prüfen müssen, ob das Feld leer ist. Wenn es leer ist, ermitteln Sie den Wert dieses Felds. Dadurch muss sichergestellt werden, dass jeglicher Zugriff auf dieses Feld, auch aus der Klasse heraus, über die Erfassungsmethode erfolgen muss.

1.2 Code-Implementierung

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

1.3 Zeitpunkt der Nutzung

Erwägen Sie die Verwendung von Lazy Loading nur, wenn die Domain zusätzlichen Datenbankzugriff erfordert.

erfordert zusätzliche Aufrufe und die bei Verwendung des Hauptobjekts aufgerufenen Daten werden nicht verwendet.

Am besten geeignet für Aktivitätsaufzeichnungen, Tabellendateneinträge und Zeilendateneinträge.

(2) Virtueller Proxy

2.1 Konzept

ist im Wesentlichen ein Objekt, das nichts enthält. Nur wenn eine seiner Methoden aufgerufen wird, werden nur dann die entsprechenden Objekte angezeigt werden aus der Datenbank geladen.

Einfach ausgedrückt handelt es sich um ein Proxy-Objekt eines Objekts. Das Objekt wird nicht während der Initialisierung geladen. Es wird nur geladen, wenn das Proxy-Objekt aufgerufen wird.

2.2 Code-Implementierung

/**
 * 虚代理,只有在被访问成员时才调用闭包函数生成目标对象。
 */
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) Wertinhaber (Wertinhaber)

3.1 Konzept

Ein Benutzer An Objekt, das ein anderes Objekt umschließt, können Sie auf den Werthalter zugreifen, um seinen Wert abzurufen, aber nur beim ersten Zugriff auf den Werthalter werden tatsächlich Daten aus der Datenbank gelesen.

(4) Ghost (Geist)

4.1 Konzept

Ein reales Objekt im Teilzustand. Beim Laden eines Objekts aus der Datenbank enthält es nur seine ID. Bei jedem Zugriff auf eine Domain wird der vollständige Status geladen. Stellen Sie sich einen Geist als ein Objekt vor, bei dem jedes seiner Felder auf einmal langsam initialisiert wird, oder als einen virtuellen Proxy, bei dem das Objekt selbst sein virtueller Proxy ist.

4.2 Code-Implementierung

//继承要加载的对象
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;
    }
}

3. Risiken eines verzögerten Ladens

1. Wenn Sie Ghosting verwenden möchten, müssen Sie wissen, welche Art von Ghost Sie erstellen möchten. Dies ist oft schwer zu erkennen, wenn die Daten nicht korrekt geladen werden. Virtuelle Proxys leiden in statisch typisierten Sprachen unter dem gleichen Problem.

2. Ein verzögertes Laden kann leicht zu mehr Datenbankzugriffen als erforderlich führen. Alias ​​​​im Buch „Fluktuationsbelastung“. Verwenden Sie beispielsweise Lazy Loading, um eine Sammlung zu füllen, und greifen Sie dann jeweils nur auf ein Element zu. Auf diese Weise wird bei jedem Zugriff auf ein Objekt auf die Datenbank zugegriffen, anstatt alle benötigten Objekte auf einmal auszulesen. Diese Lademethode beeinträchtigt die Leistung des Systems erheblich. Anstatt verzögert geladene Sammlungen zu verwenden, können Sie natürlich auch die Klassensammlung selbst verzögert laden, indem Sie beim Laden der Klassensammlung den gesamten Inhalt auf einmal laden.

4. Zusammenfassung

Lazy Loading eignet sich sehr gut für aspektorientierte Programmierung (AOP). Der Lazy-Loading-Vorgang kann in einem separaten Aspekt platziert werden, sodass die Lazy-Loading-Strategie unabhängig geändert werden kann und Domänenentwickler sich nicht mit Lazy-Loading-Problemen befassen müssen.

Lazy Loading ist eine gute Praxis, unabhängig davon, ob Sie Lazy Loading-Code explizit in Domänenklassen hinzufügen oder nicht. Der Vorteil der Verwendung eines Sammlungsobjekts anstelle eines Arrays besteht neben der Typsicherheit darin, dass Sie Lazy Loading verwenden können.


Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn