[php]Collection跟持久化工廠

來源:互聯網
上載者:User
[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 < 0 || $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包分離開來。

  • 聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.