我对Data Mapper pattern很陌生。我想我错过了一些东西,因为对我来说,它失败了比最基本的例子更复杂的东西。
假设我有一个由网页组成的简单网站:
class Page {
private $id = null;
private $parent = null;
private $title = null;
private $body = null;
public function setId($id) { $this->id = (int) $id; }
public function setParent(Page $parent) { $this->parent = $parent; }
public function setTitle($title) { $this->title = $title; }
public function setBody($body) { $this->body = $body; }
public function getId() { return $this->id; }
public function getParent() { return $this->parent; }
public function getTitle() { return $this->title; }
public function getBody() { return $this->body; }
}
现在我想实例化树中深处的 :
class PageMapper {
public function fetch($id) {
//...
$data = $db->fetchRow("SELECT * FROM `pages` WHERE `id` = ?", $id);
$page = new Page();
$page->setId($data['id']);
$page->setTitle($data['title']);
$page->setBody($data['body']);
if ($data['parent_id'] !== null) {
$page->setParent(
$this->fetch($data['parent_id']);
);
}
}
public function save(Page $page) {
//...
}
}
问题很明显:我必须将所有父母一直实例化到根页面。
现在想象一个页面需要知道它的孩子。这意味着,如果我想要实例化根页面,我将必须加载整个树。
解决方案可能是父/子只会按需加载,但这意味着域对象必须知道映射器以便从中提取数据......并且分离将会消失
域模型( Page 类的实例)应该对Data Mapper层(分离)一无所知,但仍然能够执行这些任务(检索父/子)。
在这些条件下是否可以分离关注点?如果是,怎么样?
答案 0 :(得分:1)
查看Doctrine,一个实现数据映射器模式的orm框架:
你的方法的问题不是整个树(孩子)的实例化,而是 它将使用的查询量。
看一下教义方法,你会有一个子属性,一次只能用一个查询加载。
我也绝不会建议为一个orm实现一个自制的解决方案。
可能的解决方案也是使用Closure:
class Page {
//...
public function setParents(Closure $pages)
{
$this->parents = $pages;
}
}
class PagesMapper {
public function fetch() {
//fetch the page ...
$parents = function($parent) use($id, $db) {
parents = $db->query(/* select parent... */);
$pages = array();
foreach($parents as $parent) {
$page = new Page();
$page->id = $parent->id;
//...
$pages[] = $page;
}
return $pages;
};
$page->setParents($parents);
return $page;
}
}
因此页面域不知道持久层。