代码改变世界

转:ZendFramework中领域逻辑的处理

2012-02-01 16:18  马哈鱼  阅读(372)  评论(0编辑  收藏  举报

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的指导思想迥然不同,走的完全是两条路。

转自:http://hi.baidu.com/thinkinginlamp/blog/item/0637d0166fbb851c972b4390.html