代码之家  ›  专栏  ›  技术社区  ›  Noah Goodrich

如何在Zend框架中设计域层对象来表示多个对象和单个对象?

  •  6
  • Noah Goodrich  · 技术社区  · 16 年前

    我正致力于在Zend框架中创建一个独立于数据访问层的域层。数据访问层由两个主要对象组成:表数据网关和行数据网关。根据Bill Karwin的回复 this earlier question 现在我的域人员对象有以下代码:

    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)
        {
    
        }
    }
    

    但是,这只适用于单个行。我还需要创建一个域对象,它可以表示整个表,并且(大概)可以用于遍历表中的所有人员,并返回适当类型的人员(管理员、买方等)对象以供使用。基本上,我设想如下:

    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;
            }
        }
    }
    

    这是处理这个特殊问题的好方法还是坏方法?我应该对总体设计做哪些改进或调整?

    提前感谢您的评论和批评。

    1 回复  |  直到 15 年前
        1
  •  9
  •   Bill Karwin    16 年前

    我记得您将使用域模型类来完全隐藏这样一个事实:您正在使用数据库表进行持久化。所以传递一个表对象或行对象应该完全在下面:

    <?php
    require_once 'Zend/Loader.php';
    Zend_Loader::registerAutoload();
    
    $db = Zend_Db::factory('mysqli', array('dbname'=>'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 总是坏的,或者你有什么。做出如此明确声明的人正试图将问题过于简单化。适当地使用语言工具,它们会对您有好处。

    也就是说,当您选择一种语言结构时,通常会有一种权衡,这使得做一些事情更容易,而做其他事情更难。人们常常指向 静止的 这使得编写单元测试代码变得困难,而且PHP还存在一些与静态和子类化相关的令人恼火的缺陷。但是也有一些好处,正如我们在这段代码中看到的。你必须根据具体情况来判断利弊。

    “Zend框架是否支持查找工具? 上课?”

    我不认为这是必要的。

    “你有什么特别的理由 已重命名要获取的find方法 模型类?”

    我给这个方法命名了 get() 只是为了区别于 find() . “getter”范式与OO接口相关,而“finder”传统上与数据库相关。我们试图设计域模型来假装不涉及数据库。

    “您是否可以继续使用 实现特定getby的相同逻辑 和getcollection by methods?“

    我会抵制创建一个通用的 getBy() 方法,因为它很容易让它接受通用的SQL表达式,然后将其逐字传递给数据访问对象。这将域模型的使用与底层数据库表示相结合。