>  기사  >  백엔드 개발  >  객체 관계 동작 패턴 지연 로딩

객체 관계 동작 패턴 지연 로딩

巴扎黑
巴扎黑원래의
2016-11-12 10:19:04970검색

1. 개념

지연 로드: 필요한 모든 데이터를 포함하지는 않지만 데이터를 얻는 방법을 알고 있는 개체입니다.

지연 로딩은 데이터베이스 소비를 줄이기 위해 필요할 때 데이터베이스에서 데이터를 얻는 것입니다. 그러나 여전히 많은 트릭이 관련되어 있습니다.

2. 지연 로딩 구현

지연 로딩 구현에는 지연된 초기화, 가상 프록시, 값 보유자 및 고스팅의 네 가지 주요 방법이 있습니다.

(1) 지연 초기화(Lazy 초기화)

1.1 개념

가장 간단한 방법입니다. 즉, 속성 필드에 액세스할 때마다 먼저 필드가 비어 있는지 확인하고 비어 있으면 이 필드의 값을 가져와야 합니다. 이는 클래스 내에서도 이 필드에 대한 모든 액세스가 획득 방법을 통해 달성되어야 함을 보장해야 합니다.

1.2 코드 구현

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

1.3 사용 시기

도메인에 추가 데이터베이스 액세스가 필요한 경우에만 지연 로딩 사용을 고려하세요.

은 추가 호출이 필요하며, 메인 객체 사용 시 호출되는 데이터는 사용되지 않습니다.

활동 기록, 테이블 데이터 항목 및 행 데이터 항목에 가장 적합합니다.

(2) 가상 프록시

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) Valueholder(값 보유자)

3.1 Concept

사용자 An 기본 개체를 가져오려면 값 홀더에 액세스하여 해당 값을 가져올 수 있지만 값 홀더에 처음 액세스할 때만 실제로 데이터베이스에서 데이터를 읽습니다.

(4) 고스트(ghost)

4.1 개념

부분 상태의 실제 객체를 데이터베이스에서 로드할 때 포함한다. 그 아이디만요. 도메인에 액세스할 때마다 전체 상태가 로드됩니다. 고스트를 각 필드가 한 번에 느리게 초기화되는 객체로 생각하거나, 객체 자체가 가상 프록시인 가상 프록시로 생각하세요.

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;
    }
}

3. 지연 로딩의 위험

1. 상속으로 인해 종종 문제가 발생합니다. 고스팅을 사용하려면 어떤 유형의 고스트를 생성하려는지 알아야 하는데, 이는 데이터가 올바르게 로드되지 않았는지 확인하기 어려운 경우가 많습니다. 가상 프록시는 정적으로 유형이 지정된 언어에서 동일한 문제를 겪습니다.

2. 로딩이 지연되면 필요한 것보다 더 많은 데이터베이스 액세스가 발생할 수 있습니다. 책에 나오는 또 다른 이름은 "변동 로딩"입니다. 예를 들어 지연 로딩을 사용하여 컬렉션을 채운 다음 한 번에 하나의 요소에만 액세스합니다. 이러한 방식으로, 필요한 모든 개체를 한 번에 읽는 대신 개체에 액세스할 때마다 데이터베이스에 액세스하게 됩니다. 이 로딩 방법은 시스템 성능에 심각한 영향을 미칩니다. 물론, 지연 로드 컬렉션을 사용하는 대신 클래스 컬렉션 자체를 지연 로드하도록 만들어 클래스 컬렉션을 로드할 때 전체 콘텐츠를 한 번에 로드할 수도 있습니다.

4. 요약

지연 로딩은 AOP(Aspect-Oriented) 프로그래밍에 매우 적합합니다. 지연 로딩 작업을 별도의 측면에 배치할 수 있으므로 지연 로딩 전략을 독립적으로 변경할 수 있으며 도메인 개발자는 지연 로딩 문제를 처리할 필요가 없습니다.

지연 로딩은 도메인 클래스에 지연 로딩 코드를 명시적으로 추가하는지 여부에 관계없이 좋은 습관입니다. 유형 안전성 외에도 배열 대신 컬렉션 개체를 사용하면 지연 로딩을 사용할 수 있다는 이점이 있습니다.


성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.