【转】ZendFramework中领域逻辑的处理

ZendFramework一直为人所诟病的缺点就是不能优雅的处理领域逻辑,这里谈谈我的一些解决思路:

先看看一般情况下我们都是怎么写Model,Controller的:

Model的一般写法:

class Articles extends Zend_Db_Table
{
}

Controller的一般写法:

class ArticlesController extends Zend_Controller_Action
{
    protected
$_articles;

    public function init()
    {
        
$this->_articles = new Articles();
    }

    public function createAction()
    {
        
$article = $this->_articles->createRow();

        $article->title   = 'abc';
        
$article->content = 'xyz';

        if ($id = $article->save()) {
            
$this->_redirect('...');
        } else {
            
// ...
        
}
    }

    public function readAction()
    {
        
$this->view->article = $this->_articles->fetchRow("id = 1");
    }

    public function updateAction()
    {
        
$article = $this->_articles->fetchRow("id = 1");

        $article->title   = 'abc';
        
$article->content = 'xyz';

        if ($article->save()) {
            
$this->_redirect('...');
        } else {
            
// ...
        
}
    }

    public function deleteAction()
    {
        
$article = $this->_articles->fetchRow("id = 1");

        if ($article->delete()) {
            
$this->_redirect('...');
        } else {
            
// ...
        
}
    }
}


通常我们说:Rich model is better。在上面的例子中可以明显看出:Model代码很少,Controller代码很多。一般来说这是坏味道的前兆,不过上面的CRUD例子比较简单,而且Model通过继承获得了一定的CRUD能力,也可以说是很Rich的,所以这个问题并不要紧,真正的考验是当应用包含大量的逻辑的时候怎么办。

所谓逻辑大致分两种,一种是应用逻辑,一种是领域逻辑。对一个文章对象来说,文章添加成功后发送一封邮件通知就属于应用逻辑,而怎么判断是不是热门文章就是领域逻辑。

应用逻辑和领域逻辑划分的原则就是看是否有技术的味道。有就是应用逻辑,没有就是领域逻辑。之所以这样划分是因为面向对象强调重用性,而领域逻辑是一个软件的灵魂所在,只有剥离了技术味道才有更大的重用可能性。

在ZendFramework里,我们可以把Controller看作是应用层,因为它自然的勾画了用例,所以把应用逻辑放在Controller里是说得过去的,而领域逻辑则无论如何要保证百分百在Model里。在通常的ZendFramework代码里,Model的角色一般是由Zend_Db_Table来扮演的。Zend_Db_Table属于一个表数据入口的实现。表数据入口是操作一个表的模式,而我们的对象往往只是一个行,所以很多领域逻辑不太可能加在Zend_Db_Table的层次上,而应该是Zend_Db_Table_Row的层次。

下面看如何把领域逻辑融合到Zend_Db_Table_Row中:

首先自定义一个Row类:

class Article extends Zend_Db_Table_Row
{
    public function
isHot()
    {
        
// ...
    
}
}

然后让Row类能挂接到Table类之上:

class Articles extends Zend_Db_Table
{
    protected
$_rowClass = 'Article';
}

这个时候,就可以通过Row类来使用包含领域逻辑的方法(比如:isHot方法)了:

$article = $this->_articles->fetchRow("id = 1");

if ($article->isHot()) {
    
// ...
} else {
    
// ...
}

我上面所做的一切的一切,目的只有一个:就是要把Zend_Db_Table_Row变成Rich Model!

在ZendFramework的使用中。我们可以把Zend_Db_Table当作管理领域对象生命周期的工厂或仓储使用,它里面可以有少量和领域对象生命周期相关的逻辑,比如说领域对象的组装等等。更多领域逻辑存在于Zend_Db_Table_Row对象中。

一般的操作流程应该是这样的:Zend_Db_Table里通过fetchRow或者fetchAll方法得到Zend_Db_Table_Row或者Zend_Db_Table_Rowset。然后使用Zend_Db_Table_Row去完成领域逻辑。

如果你的实体很多,挨个自定义Row类似乎很是乏味,要是ZendFramework能像CakePHP那样提供脚手架去自动生成代码就爽歪歪了,不过这是不可能的事情了。ZendFramework和CakePHP的指导思想迥然不同,走的完全是两条路。

此条目发表在 Zendframework 分类目录,贴了 , 标签。将固定链接加入收藏夹。

发表评论

电子邮件地址不会被公开。 必填项已用 * 标注

*

您可以使用这些 HTML 标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>