您好,欢迎访问一九零五行业门户网

[php]Collection跟持久化工厂

[php]collection和持久化工厂
mapper类中的findbyid($id)可以从数据库中取出指定id的一条数据,映射成一个对象返回。很多时候我们需要返回一个数据集合(findall),那我们就需要一种数据结构来保存这些数据,在需要时映射成对象。既然一条数据映射成一个对象,那么一个数据集合就需要一个对象集合。可以把数据集合和对象集合放在一个类中,这样就方便处理数据到对象的映射了。我们把这个类命名为collection,为了能更好好的访问集合对象,collection子类都实现了iterator接口,使用foreach可以方便访问。
       collection的类结构:
\demo\mapper\collection: 
namespace demo\mapper;use demo\base\appexception;use demo\domain\domainobject;use demo\mapper\mapper;abstract class collection { // 保存数据库取出的行数据 protected $raws; // 保存已映射的对象 protected $objects = array(); // 用于$raws[]到$objects的映射 protected $mapper; // 当前指针 private $pointer = 0; // 对象数组总数 private $total = 0; /** * @param array $raws 未处理过的数据库数据 * @param mapper $mapper 用于把$raws映射成对象(createobject) */ public function __construct(array $raws = null, mapper $mapper = null) { if (!is_null($raws) && !is_null($mapper)) { $this->raws = $raws; $this->total = count($raws); } $this->mapper = $mapper; } /** * 返回指定$num的数据对象 * @param int $num */ public function getrow($num) { if ($num = $this->total) { return null; } // 延迟加载 $this->notifyaccess(); if (isset($this->objects[$num])) { return $this->objects[$num]; } if (isset($this->raws[$num])) { $obj = $this->mapper->createobject($this->raws[$num]); $this->objects[$num] = $obj; return $obj; } return null; } /** * 添加对象 * @param domainobject $obj * @throws appexception */ public function add(domainobject $obj) { // 类型安全检查 $targetclass = $this->gettargetclass(); if (!($obj instanceof $targetclass)) { throw new appexception(object must be {$targetclass}); } // $this->notifyaccess(); $this->objects[$this->pointer++] = $obj; } public function current() { return $this->getrow($this->pointer); } public function next() { $obj = $this->getrow($this->pointer); if (!is_null($obj)) { $this->pointer++; } return $obj; } public function key() { return $this->pointer; } public function rewind() { $this->pointer = 0; } public function valid() { return !is_null($this->current()); } /** * 延迟加载 */ protected function notifyaccess() { // 暂时留空 } protected abstract function gettargetclass();}
\demo\domain:
namespace demo\domain;use \demo\domain\domainobject;interface classroomcollection extends \iterator { public function add(domainobject $obj);}interface studentcollection extends \iterator { public function add(domainobject $obj);}interface scorecollection extends \iterator { public function add(domainobject $obj);}
\demo\mapper:namespace demo\mapper;class classroomcollection extends collection implements \demo\domain\classroomcollection { protected function gettargetclass() { return '\demo\domain\classroom'; }}class studentcollection extends collection implements \demo\domain\studentcollection { protected function gettargetclass() { return '\demo\domain\student'; }}class scorecollection extends collection implements \demo\domain\scorecollection { protected function gettargetclass() { return '\demo\domain\score'; }}
为什么需要为domain包还需要一个collection接口呢?因为domain包需要用到collection来保存数据,为了让domain包不依赖于mapper包的collection,所以创建了一个接口。而\demo\domain\mapper\collection则会实现这个接口。
现在的结构开始有点复杂了,为了能管理好mapper和collection的具体子类,我们可以使用抽象工厂来管理对象的创建。来看看类图:
\demo\mapper\persistancefatory
namespace demo\mapper;/** * 持久化工厂 */abstract class persistancefactory { public static function getfactory($targetclass) { switch ($targetclass) { case '\demo\domain\classroom': return new classroompersistancefactory(); case '\demo\domain\student': return new studentpersistancefactory(); case '\demo\domain\score': return new scorepersistancefactory(); } } public abstract function getmapper(); public abstract function getcollection(array $raws = null);}class classroompersistancefactory extends persistancefactory { public function getmapper() { return new classroommapper(); } public function getcollection(array $raws = null) { return new classroomcollection($raws, $this->getmapper()); }}class studentpersistancefactory extends persistancefactory { public function getmapper() { return new studentmapper(); } public function getcollection(array $raws = null) { return new studentcollection($raws, $this->getmapper()); }}class scorepersistancefactory extends persistancefactory { public function getmapper() { return new scoremapper(); } public function getcollection(array $raws = null) { return new scorecollection($raws, $this->getmapper()); }}
使用这样的工厂模式可以很方便地创建指定的mapper和collection子类了,同时这种方式也可以方便以后新功能的添加。        domain包中同样需要collection对象,但需要注意和mapper中的collection分离开来。我们可以在domain包中创一个helperfactory类来当做domain访问mapper的桥梁。
namespace demo\domain;use demo\mapper\persistancefactory;class helperfactory { public static function getcollection($targetclass) { $fact = persistancefactory::getfactory($targetclass); return $fact->getcollection(); } public static function getfinder($targetclass) { $fact = persistancefactory::getfactory($targetclass); return $fact->getmapper(); }}
这样就把domain包和mapper包分离开来了。
collection有了,那么就来实现mapper的findall()吧。
namespace demo\mapper;use demo\base\appexception;use \demo\base\applicationregistry;/** * mapper */abstract class mapper { //... /** * 返回collection */ public function findall() { $pstmt = $this->getselectallstmt(); $pstmt->execute(array()); $raws = $pstmt->fetchall(\pdo::fetch_assoc); $collection = $this->getcollection($raws); return $collection; } /** * 返回子类collection * @param array $raw */ public function getcollection(array $raws) { return $this->getfactory()->getcollection($raws); } /** * 返回子类持久化工厂对象 */ public function getfactory() { return persistancefactory::getfactory($this->gettargetclass()); } //....}
例子:
$fact = persistancefactory::getfactory('\demo\domain\classroom');$mapper = $fact->getmapper();$classrooms = $mapper->findall();foreach ($classrooms as $elem) { var_dump($elem);}
colletion能方便管理$raws[]到$objects[]的映射。
        persistancefactory能管理好mapper包中类对象的创建。
        helperfactory把mapper包和domain包分离开来。
其它类似信息

推荐信息