【问题标题】:How to load child objects lazily with the Data Mapper pattern?如何使用 Data Mapper 模式延迟加载子对象?
【发布时间】:2023-03-13 19:35:01
【问题描述】:

如果我有一个相当复杂的用户模型,我想使用数据映射模式来加载,我将如何在不让用户知道 UserMapper 的情况下延迟加载一些更密集的用户信息?

例如 - 如果用户模型允许一个地址对象数组(用户可能有很多,但不一定需要预先),如果/当需要时,我将如何加载这些对象?

我是否让 User 模型知道 AddressMapper?

我是否将用户模型传回给 UserMapper,然后它只对地址进行水合?

还有更好的选择吗?

【问题讨论】:

    标签: php lazy-loading datamapper


    【解决方案1】:

    嗯,我曾经发现过以下巧妙的模式,由 Zend 框架的开发人员 Ben Scholzen 提供。它是这样的:

    class ModelRelation
        implements IteratorAggregate
    {
        protected $_iterator;
        protected $_mapper;
        protected $_method;
        protected $_arguments;
    
        public function __construct( MapperAbstract $mapper, $method, array $arguments = array() )
        {
            $this->_mapper    = $mapper;
            $this->_method    = $method;
            $this->_arguments = $arguments;
        }
    
        public function getIterator()
        {
            if( $this->_iterator === null )
            {
                $this->_iterator = call_user_func_array( array( $this->_mapper, $this->_method ), $this->_arguments );
            }
    
            return $this->_iterator;
        }
    
        public function __call( $name, array $arguments )
        {        
            return call_user_func_array( array( $this->getIterator(), $name ), $arguments );
        }
    }
    

    Ben Scholzen 的实际实现is here

    你会使用它的方式是这样的:

    class UserMapper
        extends MapperAbstract
    {
        protected $_addressMapper;
    
        public function __construct( AddressMapper $addressMapper )
        {
            $this->_addressMapper = $addressMapper;
        }
    
        public function getUserById( $id )
        {
            $userData = $this->getUserDataSomehow();
    
            $user = new User( $userData );
            $user->addresses = new ModelRelation(
                $this->_addressesMapper,
                'getAddressesByUserId',
                array( $id )
            );
    
            return $user;
        }
    }
    
    class AddressMapper
        extends MapperAbstract
    {
        public function getAddressesByUserId( $id )
        {
            $addressData = $this->getAddressDataSomehow();
    
            $addresses = new SomeAddressIterator( $addressData );
    
            return $addresses;
        }
    }
    
    $user = $userMapper->getUserById( 3 );
    foreach( $user->addresses as $address ) // calls getIterator() of ModelRelation
    {
        // whatever
    }
    

    事情是这样的;如果对象图在某些时候变得非常复杂并且嵌套很深,这可能会变得非常慢,因为映射器都必须查询自己的数据(假设您正在使用数据库进行持久性)。当我将这种模式用于 CMS 以获取嵌套的 Pages 对象(任意深度的子页面)时,我遇到了这种情况。

    它可能会通过一些缓存机制进行调整,以显着加快速度。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-06-01
      • 2019-04-29
      • 1970-01-01
      • 2011-02-06
      • 1970-01-01
      • 2020-06-13
      • 2021-07-22
      • 1970-01-01
      相关资源
      最近更新 更多