如果我有一个相当复杂的用户模型,我想使用数据映射模式加载,我怎么会懒得加载一些更密集的用户信息而不允许用户知道UserMapper?< / p>
例如 - 如果User模型允许一个Address对象数组(并且用户可能有很多这些对象,但前面不一定需要),那么如果/需要的话,如何加载这些对象?
我是否让用户模型了解AddressMapper?
我是否将用户模型BACK传递给UserMapper,然后只对地址进行水合?
有更好的选择吗?
答案 0 :(得分:7)
好吧,我一度发现了以下聪明的模式,由Zend Framework的开发人员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
对象(任意深的子页面)时,我遇到了这种情况。
可能会通过一些缓存机制进行调整,以加快速度。