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 {
// ...
}
}
}
所谓逻辑大致分两种,一种是应用逻辑,一种是领域逻辑。对一个文章对象来说,文章添加成功后发送一封邮件通知就属于应用逻辑,而怎么判断是不是热门文章就是领域逻辑。
应用逻辑和领域逻辑划分的原则就是看是否有技术的味道。有就是应用逻辑,没有就是领域逻辑。之所以这样划分是因为面向对象强调重用性,而领域逻辑是一个软件的灵魂所在,只有剥离了技术味道才有更大的重用可能性。
在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的指导思想迥然不同,走的完全是两条路。