如何设计域层对象以表示多个对象Zend框架中的单个对象? [英] How to Design Domain Layer Objects to Represent Multiple Objects & Single Object in Zend Framework?

查看:71
本文介绍了如何设计域层对象以表示多个对象Zend框架中的单个对象?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在用Zend Framework创建一个与数据访问层分开的域层.数据访问层由两个主要对象组成,一个表数据网关和一个行数据网关.根据Bill Karwin对这先前的问题的答复我的域Person对象的以下代码:

I'm working on creating a domain layer in Zend Framework that is separate from the data access layer. The Data Access Layer is composed to two main objects, a Table Data Gateway and a Row Data Gateway. As per Bill Karwin's reply to this earlier question I now have the following code for my domain Person object:

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,并返回适当类型的person(管理员,买方等)对象以供使用.基本上,我设想如下所示:

However, this only works with an individual row. I also need to create a domain object that can represent the entire table and (presumably) can be used to iterate through all of the Person's in the table and return the appropriate type of person (admin, buyer, etc) object for use. Basically, I envision something like the following:

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

这是处理此特定问题的好/坏方法吗?我应该对总体设计进行哪些改进或调整?

Is this is good/bad way to handle this particular problem? What improvements or adjustments should I make to the overall design?

预先感谢您的评论和批评.

Thanks in advance for your comments and criticisms.

推荐答案

我牢记您会使用Domain Model类来完全隐藏使用数据库表进行持久化的事实.因此,传递Table对象或Row对象应该完全在幕后:

I had in mind that you would use the Domain Model class to completely hide the fact that you're using a database table for persistence. So passing a Table object or a Row object should be completely under the covers:

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

我认为静态方法不好 这就是为什么我试图创造 表级方法作为实例 方法."

"I thought static methods were bad which is why I was trying to create the table level methods as instance methods."

我不会接受任何笼统的说法,即static总是很糟糕,或者单例总是很糟糕,或者goto总是很糟糕,或者您拥有什么.做出这样明确声明的人正在寻求简化问题.正确使用语言工具,对您会有所帮助.

I don't buy into any blanket statement that static is always bad, or singletons are always bad, or goto is always bad, or what have you. People who make such unequivocal statements are looking to oversimplify the issues. Use the language tools appropriately and they'll be good to you.

也就是说,当您选择一种语言结构时,通常会权衡取舍,这使得做某些事情变得更容易,而做其他事情则更加困难.人们经常指出static使得编写单元测试代码变得困难,而且PHP在静态和子类化方面也存在一些烦人的缺陷.但是,正如我们在这段代码中看到的那样,它也有一些优点.您必须根据具体情况自行判断优势是否大于劣势.

That said, there's often a tradeoff when you choose one language construct, it makes it easier to do some things while it's harder to do other things. People often point to static making it difficult to write unit test code, and also PHP has some annoying deficiencies related to static and subclassing. But there are also advantages, as we see in this code. You have to judge for yourself whether the advantages outweigh the disadvantages, on a case by case basis.

"Zend Framework是否将支持Finder 上课?"

"Would Zend Framework support a Finder class?"

我认为这不是必需的.

您是否有特定原因 重命名了要进入的find方法 模型课?"

"Is there a particular reason that you renamed the find method to be get in the model class?"

我将方法get()命名为与find()不同. "getter"范例与OO接口相关联,而"finders"传统上与数据库内容相关联.我们正在尝试设计域模型以假装不涉及数据库.

I named the method get() just to be distinct from find(). The "getter" paradigm is associated with OO interfaces, while "finders" are traditionally associated with database stuff. We're trying to design the Domain Model to pretend there's no database involved.

"并且您会继续使用 实现特定getBy的相同逻辑 和getCollectionBy方法?"

"And would you use continue to use the same logic to implement specific getBy and getCollectionBy methods?"

我拒绝创建通用的getBy()方法,因为它很想让它接受通用的SQL表达式,然后将其逐字传递给数据访问对象.这会将我们的域模型的使用与基础数据库表示结合起来.

I'd resist creating a generic getBy() method, because it's tempting to make it accept a generic SQL expression, and then pass it on to the data access objects verbatim. This couples the usage of our Domain Model to the underlying database representation.

这篇关于如何设计域层对象以表示多个对象Zend框架中的单个对象?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆