第12章 Controller
本章大纲
- Controller 定义
- Controller 的职责
- Web Controller
- API Controller
- Device Controller
- Event Controller
- Controller 与 Central
- Controller 与 Individual
- Controller 调用方式
- Controller 实际案例
12.1 Controller 定义
在 SAI Framework 中,Controller 是外部输入进入 SAI Framework 的控制入口层。
Controller 的核心任务不是进行认知、推理和决策,而是:
接收外部输入
↓
识别输入类型
↓
组织 Request / Event
↓
转换为 Information
↓
把 Information 交给 SAI
↓
接收 SAI 输出
↓
转换为外部结果
因此可以定义为:
Controller 是连接外部输入与 SAI Runtime 的入口控制对象。
基本结构:
External World
│
▼
Request
│
▼
Controller
│
▼
Information
│
▼
SAI
Controller 本身不应该承担:
Cognition
Reasoning
Decision
Learning
Memory
这些属于 SAI 内部功能。
12.2 Controller 的职责
Controller 可以承担以下职责:
① 接收输入
② 验证输入
③ 识别输入类型
④ 创建 Request / Event
⑤ 转换 Information
⑥ 调用 SAI Runtime
⑦ 接收执行结果
⑧ 调用 Renderer / Adapter
⑨ 返回外部结果
因此可以形成:
Input
↓
Controller
↓
Information
↓
SAI
↓
Result
↓
Controller
↓
Output
Controller 最重要的是边界转换。
例如 Web:
HTTP
↓
Controller
↓
Information
设备:
Device
↓
Controller
↓
Information
事件:
Event
↓
Controller
↓
Information
12.3 Web Controller
Web Controller 是最常见的 Controller。
例如:
Browser
↓
HTTP Request
↓
WebController
↓
Information
↓
SAI
假设浏览器发送:
GET /temperature?room=A
WebController 可以读取:
method = GET
path = /temperature
room = A
然后转换:
Information
{
type: web_request,
source: browser,
content:
{
action: get_temperature,
room: A
}
}
然后:
Information
↓
SAI
因此 WebController 不负责“思考”。
它只负责把 Web 世界的信息正确送入 SAI。
12.4 API Controller
API Controller 与 Web Controller 类似,但重点是处理 API 输入。
例如:
POST /api/device
请求:
{
"device": "fan_001",
"action": "on"
}
API Controller 接收到以后:
JSON Request
↓
API Controller
↓
Information
例如:
$information = new Information(
'api_request',
'client',
array(
'device' => 'fan_001',
'action' => 'on'
)
);
进入 SAI:
Information
↓
Perception
↓
Cognition
↓
Reasoning
↓
Decision
↓
Behavior
执行结果:
Action Result
然后 API Controller 可以把结果交给:
ApiRenderer
最终:
{
"success": true,
"device": "fan_001",
"action": "on"
}
12.5 Device Controller
SAI 不只面对 Web。
外部设备也可能产生输入。
例如:
Temperature Sensor
↓
Device Controller
↓
Information
↓
SAI
设备发送:
temperature = 32
Controller 转换为:
Information
{
type: device_request,
source: temperature_sensor,
content:
{
temperature: 32
}
}
进入:
SAI
之后 SAI 可以根据已有对象、事实和规则进行处理。
例如:
Room.temperature = 32
Fan.state = OFF
Person.state = PRESENT
规则:
IF temperature > 30
AND person = PRESENT
AND fan = OFF
THEN fan.turnOn()
Controller 并不负责执行这个推理。
它只负责:
Device Input
↓
Information
12.6 Event Controller
Event Controller 用于处理事件。
例如:
Sensor Event
System Event
Timer Event
Device Event
Task Event
事件:
device_connected
进入:
EventController
↓
Information
↓
SAI
例如:
$information = new Information(
'system_event',
'device_manager',
array(
'event' => 'device_connected',
'device_id' => 'motor_001'
)
);
SAI 可以进一步判断:
Object = motor_001
State = connected
并更新相应状态。
因此:
Event Controller 负责把外部事件转换成 SAI 可以处理的信息。
12.7 Controller 与 Central
这是 SAI Framework 中一个非常重要的区别。
Controller:
外部
↓
Controller
↓
Information
Central:
Individual
↓
Central
↓
内部模块
两者的位置不同。
完整结构:
External World
│
▼
Controller
│
▼
Information
│
▼
Individual
│
▼
Central
│
┌────┼────┐
▼ ▼ ▼
Cognition Memory Reasoning
│
▼
Decision
│
▼
Behavior
因此:
| Controller | Central |
|---|---|
| 外部入口 | 内部协调 |
| 接收外部输入 | 协调内部模块 |
| Request/Event → Information | Information → 内部处理 |
| 面向 Framework 外部 | 面向 Individual 内部 |
| 可以是 Web/API/Device/Event | 属于 Individual Runtime |
| 不是认知核心 | 也不是认知本身 |
最重要的一句话:
Controller 控制“输入如何进入系统”,Central 协调“Individual 内部如何运行”。
12.8 Controller 与 Individual
Controller 也不等于 Individual。
例如:
WebController
│
▼
Information
│
▼
Individual
Controller 是入口。
Individual 是模拟人工个体。
例如一个 SAI 系统:
WebController
DeviceController
SensorController
EventController
│
▼
Information
│
▼
Individual
│
▼
Central
一个 Individual 可以接受多个 Controller 的输入:
Individual
▲
┌──────────┼──────────┐
│ │ │
│ │ │
WebCtrl DeviceCtrl SensorCtrl
因此 Controller 是:
入口对象
Individual 是:
模拟人工个体
两者不能混为一谈。
12.9 Controller 调用方式
Controller 调用 SAI,可以设计成多种方式。
最简单:
Controller
↓
Central
但更清晰的设计是:
Controller
↓
Information
↓
Application / Runtime
↓
Individual
↓
Central
例如:
$information = $controller->receive(
$request
);
$result = $application->process(
$information
);
这里:
Controller
负责:
receive()
而:
Application / Runtime
负责:
process()
这样 Controller 不需要知道 SAI 内部每一个模块的具体实现。
12.10 Controller 基类
可以设计一个简单的 Controller 基类:
<?php
namespace SAI\Core;
abstract class Controller
{
protected $application;
public function __construct(
$application
) {
$this->application = $application;
}
abstract public function handle(
$request
);
}
这样不同 Controller 可以继承:
Controller
│
├── WebController
├── ApiController
├── DeviceController
└── EventController
12.11 WebController
例如:
<?php
namespace SAI\Controller;
use SAI\Core\Controller;
use SAI\Information\Information;
class WebController extends Controller
{
public function handle($request)
{
return new Information(
'web_request',
'browser',
array(
'method' => $request->getMethod(),
'path' => $request->getPath()
)
);
}
}
它的任务非常明确:
Request
↓
WebController
↓
Information
而不是:
WebController
↓
Reasoning
↓
Decision
12.12 DeviceController
<?php
namespace SAI\Controller;
use SAI\Core\Controller;
use SAI\Information\Information;
class DeviceController extends Controller
{
public function handle($request)
{
return new Information(
'device_request',
$request['device'],
$request['content']
);
}
}
调用:
$information = $deviceController->handle(
array(
'device' => 'temperature_sensor',
'content' => array(
'temperature' => 32
)
)
);
得到:
Information
type = device_request
source = temperature_sensor
content.temperature = 32
12.13 EventController
<?php
namespace SAI\Controller;
use SAI\Core\Controller;
use SAI\Information\Information;
class EventController extends Controller
{
public function handle($event)
{
return new Information(
'system_event',
'event_system',
$event
);
}
}
例如:
$information = $eventController->handle(
array(
'event' => 'device_connected',
'device_id' => 'motor_001'
)
);
12.14 Controller 实际案例
下面建立一个完整的教程案例:
Web Request
↓
WebController
↓
Information
↓
Individual
说明:下面代码属于本章教程示例,用于展示 Controller 的职责与调用关系,不代表已经在实际环境中创建或验证。
目录:
sai-controller-demo/
│
├── app/
│ ├── Core/
│ │ ├── Controller.php
│ │ └── Request.php
│ │
│ ├── Information/
│ │ └── Information.php
│ │
│ ├── Controller/
│ │ └── WebController.php
│ │
│ └── Individual/
│ └── Individual.php
│
├── bootstrap.php
└── index.php
12.14.1 Request.php
<?php
namespace SAI\Core;
class Request
{
protected $method;
protected $path;
protected $query;
public function __construct(
$method,
$path,
array $query = array()
) {
$this->method = $method;
$this->path = $path;
$this->query = $query;
}
public function getMethod()
{
return $this->method;
}
public function getPath()
{
return $this->path;
}
public function getQuery($name)
{
return isset($this->query[$name])
? $this->query[$name]
: null;
}
}
12.14.2 Controller.php
<?php
namespace SAI\Core;
abstract class Controller
{
protected $application;
public function __construct(
$application = null
) {
$this->application = $application;
}
abstract public function handle(
$request
);
}
12.14.3 Information.php
<?php
namespace SAI\Information;
class Information
{
protected $type;
protected $source;
protected $content;
public function __construct(
$type,
$source,
$content
) {
$this->type = $type;
$this->source = $source;
$this->content = $content;
}
public function getType()
{
return $this->type;
}
public function getSource()
{
return $this->source;
}
public function getContent()
{
return $this->content;
}
}
12.14.4 WebController.php
<?php
namespace SAI\Controller;
use SAI\Core\Controller;
use SAI\Information\Information;
class WebController extends Controller
{
public function handle($request)
{
return new Information(
'web_request',
'browser',
array(
'method' => $request->getMethod(),
'path' => $request->getPath(),
'action' => $request->getQuery('action')
)
);
}
}
12.14.5 Individual.php
<?php
namespace SAI\Individual;
class Individual
{
protected $id;
protected $name;
protected $state;
public function __construct(
$id,
$name
) {
$this->id = $id;
$this->name = $name;
$this->state = 'created';
}
public function start()
{
$this->state = 'running';
}
public function getId()
{
return $this->id;
}
public function getName()
{
return $this->name;
}
public function getState()
{
return $this->state;
}
}
12.15 Bootstrap
<?php
error_reporting(E_ALL);
ini_set('display_errors', '1');
spl_autoload_register(function ($class) {
$prefix = 'SAI\\';
if (strpos($class, $prefix) !== 0) {
return;
}
$relative = substr(
$class,
strlen($prefix)
);
$file = __DIR__
. '/app/'
. str_replace(
'\\',
'/',
$relative
)
. '.php';
if (is_file($file)) {
require_once $file;
}
});
12.16 index.php
<?php
require_once __DIR__ . '/bootstrap.php';
use SAI\Core\Request;
use SAI\Controller\WebController;
use SAI\Individual\Individual;
$request = new Request(
isset($_SERVER['REQUEST_METHOD'])
? $_SERVER['REQUEST_METHOD']
: 'CLI',
isset($_SERVER['REQUEST_URI'])
? $_SERVER['REQUEST_URI']
: '/',
$_GET
);
$individual = new Individual(
'sai_001',
'Indoor SAI'
);
$individual->start();
$controller = new WebController();
$information = $controller->handle(
$request
);
echo '<pre>';
echo "Controller: WebController"
. PHP_EOL;
echo "Information Type: "
. $information->getType()
. PHP_EOL;
echo "Information Source: "
. $information->getSource()
. PHP_EOL;
echo "Action: "
. $information->getContent()['action']
. PHP_EOL;
echo "Individual: "
. $individual->getName()
. PHP_EOL;
echo "Individual State: "
. $individual->getState()
. PHP_EOL;
echo '</pre>';
访问:
/index.php?action=temperature
按照上述代码,预期得到:
Controller: WebController
Information Type: web_request
Information Source: browser
Action: temperature
Individual: Indoor SAI
Individual State: running
同样需要明确:
这是根据教程代码得到的预期运行结果,并非本次实际执行验证结果。
12.17 Controller 的完整调用链
现在把整个案例连接起来:
Browser
│
│ HTTP Request
▼
Request
│
▼
WebController
│
│ handle()
▼
Information
│
▼
Individual
│
▼
Central
│
▼
Cognition / Memory / Reasoning
│
▼
Decision
│
▼
Behavior
如果是 Web 输出:
Behavior
↓
Expression
↓
WebRenderer
↓
Response
↓
Browser
因此完整 Web SAI:
Browser
↓
HTTP Request
↓
Request
↓
WebController
↓
Information
↓
Individual
↓
Central
↓
Cognition
↓
Memory
↓
Reasoning
↓
Decision
↓
Behavior
↓
Expression
↓
WebRenderer
↓
Response
↓
Browser
12.18 多种 Controller 统一进入 SAI
SAI Framework 可以同时拥有多个 Controller:
SAI Framework
│
Information
▲
┌───────────┼───────────┐
│ │ │
│ │ │
WebController ApiController DeviceController
│ │ │
Web Request API Request Device Event
再加上事件:
EventController
│
▼
System Event
最终:
Web
│
▼
WebController ──────┐
│
API │
│ │
▼ │
ApiController ──────┤
│
Device │
│ │
▼ │
DeviceController ───┤
├──→ Information → SAI
Event │
│ │
▼ │
EventController ────┘
这样 SAI 核心就不需要关心:
输入来自哪里?
它只接收标准化后的:
Information
12.19 Controller 的边界
Controller 最容易出现的问题,就是承担太多职责。
例如错误设计:
Controller
├── Request
├── Information
├── Cognition
├── Memory
├── Reasoning
├── Decision
├── Learning
└── Response
这样 Controller 会变成“超级类”。
更合理的是:
Controller
│
└── 输入转换
│
▼
Information
│
▼
SAI
SAI 内部:
Information
↓
Perception
↓
Cognition
↓
Memory
↓
Reasoning
↓
Decision
↓
Behavior
输出:
Behavior
↓
Expression / Action
↓
Renderer / Adapter
↓
External World
本章小结
Controller 是 SAI Framework 的外部输入控制层。
它主要解决:
外部输入
↓
Request / Event
↓
Information
↓
SAI
不同场景可以使用不同 Controller:
WebController
ApiController
DeviceController
EventController
它们最终都可以统一进入:
Information
最重要的是理解 Controller 与 Central 的区别:
Controller
↓
外部输入
↓
Information
而:
Central
↓
Individual内部协调
↓
Cognition / Memory / Reasoning / Decision / Behavior
因此:
Controller 是外部入口,Central 是 Individual 内部协调中心。
完整架构现在可以连接为:
Bootstrap
↓
Application
↓
Container
↓
Controller
↓
Request / Event / Sensor
↓
Information
↓
Individual
↓
Central
↓
Cognition
↓
Memory
↓
Reasoning
↓
Decision
↓
Behavior
↓
Expression / Action
↓
Renderer / Adapter
↓
Response / Device
到这里,第8章 Application、第9章 Bootstrap、第10章 Container、第11章 Request/Response、第12章 Controller 已经形成完整的基础 Framework 链路:
Bootstrap
↓
Application
↓
Container
↓
Controller
↓
Information
↓
Individual
下一章进入 第13章 Model,重点就可以解决另一个核心问题:
Controller
↓
Information
↓
Model / Object
↓
SAI
并进一步明确 传统 Web Model 与 SAI Object、Property、State、Relation、Fact、Memory 数据对象之间的区别。