前端控制器已经能很好地在一个地方集中处理请求并选择适当的Command了,但是Command子类对象自己处理了视图的分配工作。要是能够使用一个类(根据Command处理后返回的状态值)来决定视图并返回到前端控制器,再由前端控制器来调用视图显示,这样的话前端控制器就处于视图层和业务层的中间了,而且也很好地把Command和视图分开了。应用控制器是个好的解决方案。
应用控制器负责映射请求到命令,并映射命令到视图。它允许改变应用程序的流程而不需要修改核心代码。它能把Command类解放出来,让Command类集中精力完成自己的工作,包括处理输入、调用应用程序逻辑和处理结果等。
应用控制器是一个类(或者一组类),它帮助前端控制接管处理请求的任务而且又把适当的视图返回给前端控制器调用。那么应用控制是什么方式运行的呢?它是通过一个xml配置文件来决定Command和视图工作的方式。比如下面这个xml文件(有点像struts的方式):
[html]
<?xml version="1.0" encoding="UTF-8"?>
<options>
<dsn>sqlite://data/demo.db</dsn>
<username>root</username>
<password>root</password>
<controller>
<view>main</view>
<view status="CMD_OK">main</view>
<view status="CMD_ERROR">error</view>
<command name="ListStudents">
<view>list_students</view>
</command>
<command name="AddStudent">
<view>add_student</view>
<status value="CMD_OK">
<forward>ListStudents</forward>
</status>
</command>
<command name="SimpleAddStudent">
<classalias name="AddStudent"/>
<view>易做图_add_student</view>
</command>
</controller>
</options>
可以看到xml中<command>中可以包含<view>、<status>、<forward>三类子元素,分别表示的是Command对应的视图、Command处理业务后的状态值、Command处理后的跳转(这里跳转到另一个Command)。
从xml的结构就能了解到Command类需要一些新的属性status了。
[php]
namespace demo\command;
/**
* 抽象父类
*/
abstract class Command {
// 状态值映射
private static $STATUS_STRINGS = array(
'CMD_DEFAULT' => 0,
'CMD_OK' => 1,
'CMD_ERROR' => 2,
'CMD_INSUFFICIENT_DATA' => 3
);
// 当前状态值
private $status = 0;
public final function __construct() {
// 子类不能重写构造函数
}
/**
* 按状态字符串返回状态值
* @param unknown_type $staStr
*/
public static function status($stauStr = 'CMD_DEFAULT') {
if (empty($stauStr)) {
$stauStr = 'CMD_DEFAULT';
}
return self::$STATUS_STRINGS[$stauStr];
}
/**
* 调用子类实现的doExecute
* @param \demo\controller\Request $request
*/
public function execute(\demo\controller\Request $request) {
$this->doExecute($request);
}
protected abstract function doExecute(\demo\controller\Request $request);
}
系统中有个专门获取配置的助手类ApplicationHelper可以实现对xml配置的读取。由于xml中的元素结构相对灵活一些,那么就需要一个ControllerMap来管理各元素中的值和Command、视图的一一映射关系。
[php]
namespace demo\controller;
class ControllerMap {
private $classrootMap = array();
private $forwardMap = array();
private $viewMap = array();
public function addClassroot($cmd, $classroot) {
$this->classrootMap[$cmd] = $classroot;
}
public function getClassroot($cmd) {
if (isset($this->classrootMap[$cmd])) {
return $this->classrootMap[$cmd];
}
return $cmd;
}
public function addForward($cmd = 'default', $status = 0, $newCmd) {
$this->forwardMap[$cmd][$status] = $newCmd;
}
public function getForward($cmd, $status) {
if (isset($this->forwardMap[$cmd][$status])) {
return $this->forwardMap[$cmd][$status];
}
return null;
}
public function addView($cmd = 'default', $status = 0, $view) {