我正在研究在Zend Framework中创建一个与数据访问层分开的域层.数据访问层由两个主要对象组成,即表数据网关和行数据网关.根据Bill Karwin对此前一个问题的回复,我现在为我的域Person对象提供了以下代码:
class Model_Row_Person { protected $_gateway; public function __construct(Zend_Db_Table_Row $gateway) { $this->_gateway = $gateway; } public function login($userName, $password) { } public function setPassword($password) { } }
但是,这仅适用于单个行.我还需要创建一个可以表示整个表的域对象,并且(可能)可以用来遍历表中的所有Person并返回适当类型的人(管理员,买家等)对象以供使用.基本上,我想象如下:
class Model_Table_Person implements SeekableIterator, Countable, ArrayAccess { protected $_gateway; public function __construct(Model_DbTable_Person $gateway) { $this->_gateway = $gateway; } public function current() { $current = $this->_gateway->fetchRow($this->_pointer); return $this->_getUser($current); } private function _getUser(Zend_Db_Table_Row $current) { switch($current->userType) { case 'admin': return new Model_Row_Administrator($current); break; case 'associate': return new Model_Row_Associate($current); break; } } }
这是处理这个特殊问题的好/坏方法吗?我应该对整体设计做出哪些改进或调整?
提前感谢您的评论和批评.
我记得你会使用Domain Model类来完全隐藏你使用数据库表进行持久化的事实.因此,传递Table对象或Row对象应完全在幕后:
'test', 'username'=>'root', 'password'=>'xxxx')); Zend_Db_Table_Abstract::setDefaultAdapter($db); class Table_Person extends Zend_Db_Table_Abstract { protected $_name = 'person'; } class Model_Person { /** @var Zend_Db_Table */ protected static $table = null; /** @var Zend_Db_Table_Row */ protected $person; public static function init() { if (self::$table == null) { self::$table = new Table_Person(); } } protected static function factory(Zend_Db_Table_Row $personRow) { $personClass = 'Model_Person_' . ucfirst($personRow->person_type); return new $personClass($personRow); } public static function get($id) { self::init(); $personRow = self::$table->find($id)->current(); return self::factory($personRow); } public static function getCollection() { self::init(); $personRowset = self::$table->fetchAll(); $personArray = array(); foreach ($personRowset as $person) { $personArray[] = self::factory($person); } return $personArray; } // protected constructor can only be called from this class, e.g. factory() protected function __construct(Zend_Db_Table_Row $personRow) { $this->person = $personRow; } public function login($password) { if ($this->person->password_hash == hash('sha256', $this->person->password_salt . $password)) { return true; } else { return false; } } public function setPassword($newPassword) { $this->person->password_hash = hash('sha256', $this->person->password_salt . $newPassword); $this->person->save(); } } class Model_Person_Admin extends Model_Person { } class Model_Person_Associate extends Model_Person { } $person = Model_Person::get(1); print "Got object of type ".get_class($person)."\n"; $person->setPassword('potrzebie'); $people = Model_Person::getCollection(); print "Got ".count($people)." people objects:\n"; foreach ($people as $i => $person) { print "\t$i: ".get_class($person)."\n"; }
"我认为静态方法很糟糕,这就是我尝试创建表级方法作为实例方法的原因."
我不买任何static
总是不好的一揽子陈述,或者单身总是坏的,或goto
总是坏的,或者你有什么.做出这种明确陈述的人正在寻求过度简化问题.适当使用语言工具,它们对你有好处.
也就是说,当你选择一种语言结构时,通常需要权衡,这使得做某些事情变得更容易,而做其他事情则更难.人们经常指出static
编写单元测试代码很困难,而且PHP也有一些与静态和子类相关的烦人缺陷.但正如我们在此代码中看到的那样,还有一些优点.您必须根据具体情况自行判断优势是否超过劣势.
"Zend Framework会支持Finder课吗?"
我不认为这是必要的.
"您是否有特殊原因要将find方法重命名为模型类?"
我将该方法命名get()
为与众不同find()
."getter"范例与OO接口相关联,而"finders"传统上与数据库内容相关联.我们正在尝试设计域模型以假装没有涉及数据库.
"你会继续使用相同的逻辑来实现特定的getBy和getCollectionBy方法吗?"
我反对创建一个泛型getBy()
方法,因为它很容易让它接受一个通用的SQL表达式,然后逐字传递给数据访问对象.这将我们的域模型的使用耦合到底层数据库表示.