首页 理论 架构 工程 文档 白皮书 著作 研究 案例 下载 博客 关于 开始使用 →

第79章 自定义 Renderer

第79章 自定义 Renderer

第61章建立了 Renderer 的基本概念:

Expression
    ↓
Template
    ↓
Renderer
    ↓
Rendered Result
    ↓
Adapter
    ↓
External Environment

第62章的 WebRenderer、第63章的 ApiRenderer,则说明了 Renderer 可以针对不同输出环境进行具体实现。

因此,自定义 Renderer 的作用是:

根据具体表现环境和输出要求,将 ICAI 已经形成的结构化 Expression 按确定规则转换成目标表现格式。

Renderer 不负责:

  • 感知
  • 认知
  • 理解
  • 推理
  • 决策
  • 学习
  • 生成新的知识

它只负责表现转换


1. Renderer Interface

Renderer Interface 是所有 Renderer 遵循的统一接口。

基本定义:

interface RendererInterface
{
    public function getId();

    public function getName();

    public function getVersion();

    public function supports($type);

    public function render($expression, $template = null);

    public function getState();
}

这样不同 Renderer 都可以被统一管理。

例如:

WebRenderer
ApiRenderer
DeviceRenderer
UiRenderer
JsonRenderer
XmlRenderer
CustomRenderer

统一形成:

RendererInterface
       ↓
具体 Renderer

Interface 的职责

Interface 规定:

Renderer
 ├── Identity
 ├── Version
 ├── Supported Type
 ├── Render
 └── State

但是不规定具体表现形式。

例如:

WebRenderer
    → HTML

ApiRenderer
    → JSON

DeviceRenderer
    → Device Data

CustomRenderer
    → 自定义格式

因此:

RendererInterface
    = 统一标准

Renderer
    = 具体表现转换

Adapter
    = 输出连接

2. 创建 Renderer

创建自定义 Renderer 首先要明确:

输入是什么?
输出是什么?
转换规则是什么?

例如创建:

StatusRenderer

它负责把系统中的状态 Expression 转换为简单的状态结构。

输入:

Expression
{
    type: "STATE",
    target: "Motor_A",
    data: {
        state: "RUNNING",
        temperature: 65
    }
}

输出:

{
    "device": "Motor_A",
    "state": "RUNNING",
    "temperature": 65
}

创建:

class StatusRenderer implements RendererInterface
{
    protected $state = 'READY';

    public function getId()
    {
        return 'status';
    }

    public function getName()
    {
        return 'Status Renderer';
    }

    public function getVersion()
    {
        return '1.0.0';
    }

    public function supports($type)
    {
        return $type === 'STATE';
    }

    public function render($expression, $template = null)
    {
        if (!is_array($expression)) {
            $this->state = 'ERROR';

            return array(
                'state' => 'FAILED',
                'error' => 'Invalid expression'
            );
        }

        if (!$this->supports(
            isset($expression['type'])
                ? $expression['type']
                : null
        )) {
            $this->state = 'ERROR';

            return array(
                'state' => 'FAILED',
                'error' => 'Unsupported expression type'
            );
        }

        $this->state = 'RUNNING';

        $data = isset($expression['data'])
            ? $expression['data']
            : array();

        $result = array(
            'device' => isset($expression['target'])
                ? $expression['target']
                : null,
            'state' => isset($data['state'])
                ? $data['state']
                : 'UNKNOWN',
            'temperature' => isset($data['temperature'])
                ? $data['temperature']
                : null
        );

        $this->state = 'READY';

        return array(
            'state' => 'SUCCESS',
            'output' => $result
        );
    }

    public function getState()
    {
        return $this->state;
    }
}

这个 Renderer 的工作非常明确:

STATE Expression
        ↓
StatusRenderer
        ↓
Status Output

3. Renderer 注册

Renderer 创建后,需要进入 Renderer Manager。

可以建立:

class RendererManager
{
    protected $renderers = array();

    public function register(RendererInterface $renderer)
    {
        $id = $renderer->getId();

        $this->renderers[$id] = $renderer;

        return true;
    }

    public function get($id)
    {
        if (!isset($this->renderers[$id])) {
            return null;
        }

        return $this->renderers[$id];
    }

    public function render(
        $id,
        $expression,
        $template = null
    ) {
        $renderer = $this->get($id);

        if (!$renderer) {
            return array(
                'state' => 'FAILED',
                'error' => 'Renderer not found'
            );
        }

        return $renderer->render(
            $expression,
            $template
        );
    }
}

注册:

$manager = new RendererManager();

$renderer = new StatusRenderer();

$manager->register($renderer);

形成:

RendererManager
       ↓
status
       ↓
StatusRenderer

Renderer Registry

如果需要持久化管理,还可以建立 Renderer Registry:

RendererRegistry
{
    id
    name
    class
    version
    path
    supported_types
    state
    enabled
}

例如:

{
    "id": "status",
    "name": "Status Renderer",
    "class": "StatusRenderer",
    "version": "1.0.0",
    "path": "renderers/StatusRenderer.php",
    "supported_types": [
        "STATE"
    ],
    "state": "REGISTERED",
    "enabled": true
}

因此:

Registry
    = 记录 Renderer

Manager
    = 管理 Renderer

Renderer
    = 执行表现转换

4. Expression 转换

Renderer 的核心就是:

Expression
    ↓
Render
    ↓
Rendered Result

例如 ICAI 已经形成:

Expression
{
    id: 2001,
    type: "STATE",
    target: "Motor_A",
    data: {
        state: "RUNNING",
        temperature: 65
    }
}

Renderer 不应该重新判断:

Motor_A 是否应该运行?

这个问题已经由:

Reasoning
Decision
Behavior
Action

完成。

Renderer 只负责:

STATE
+
Motor_A
+
RUNNING
+
65

转换为目标表现结构。

例如:

{
    "device": "Motor_A",
    "state": "RUNNING",
    "temperature": 65
}

所以:

Expression
    = 表现什么

Renderer
    = 转换成什么表现格式

Expression → Renderer

完整过程:

Expression
   ↓
Validate
   ↓
Check Type
   ↓
Check Supported
   ↓
Extract Data
   ↓
Apply Render Rules
   ↓
Build Output
   ↓
Rendered Result

如果 Expression 类型不支持:

Expression.type = ACTION

而:

StatusRenderer
supports = STATE

则不能继续转换:

StatusRenderer
    ↓
UNSUPPORTED

不能为了得到结果而强行解释。


5. 输出结果

Renderer 输出应该形成明确的 Rendered Result。

例如:

RenderedResult
{
    id
    renderer_id
    expression_id
    type
    output
    format
    state
    error
    created_at
}

例如:

{
    "id": 5001,
    "renderer_id": "status",
    "expression_id": 2001,
    "type": "STATE",
    "output": {
        "device": "Motor_A",
        "state": "RUNNING",
        "temperature": 65
    },
    "format": "STATUS",
    "state": "SUCCESS",
    "error": null
}

Renderer 输出失败

例如 Expression 缺少必要数据:

Expression
{
    type: "STATE",
    target: "Motor_A"
}

如果 Renderer 要求:

data.state

则应该返回:

RenderedResult
{
    state: "FAILED",
    error: "State data is required"
}

不能自行补充:

state = RUNNING

因为这个状态并没有来自 Expression 的依据。

这也是 ICAI 表现层的重要原则:

Renderer 可以转换已有数据,但不能凭空增加未经确定的信息。


6. 自定义 Renderer 实例

下面建立一个更加完整的:

DeviceStatusRenderer

它把 ICAI 的 Device State Expression 转换成统一的设备状态 JSON 数据结构。


6.1 输入 Expression

Expression
{
    id: 3001,
    type: "DEVICE_STATE",
    target: "Motor_A",
    data: {
        state: "RUNNING",
        speed: 50,
        temperature: 65
    }
}

6.2 Renderer

class DeviceStatusRenderer implements RendererInterface
{
    protected $state = 'READY';

    public function getId()
    {
        return 'device_status';
    }

    public function getName()
    {
        return 'Device Status Renderer';
    }

    public function getVersion()
    {
        return '1.0.0';
    }

    public function supports($type)
    {
        return $type === 'DEVICE_STATE';
    }

    public function render($expression, $template = null)
    {
        if (!is_array($expression)) {
            $this->state = 'ERROR';

            return array(
                'state' => 'FAILED',
                'error' => 'Invalid expression'
            );
        }

        $type = isset($expression['type'])
            ? $expression['type']
            : null;

        if (!$this->supports($type)) {
            $this->state = 'ERROR';

            return array(
                'state' => 'FAILED',
                'error' => 'Unsupported expression type'
            );
        }

        if (!isset($expression['target'])) {
            $this->state = 'ERROR';

            return array(
                'state' => 'FAILED',
                'error' => 'Target is required'
            );
        }

        $data = isset($expression['data'])
            ? $expression['data']
            : array();

        if (!isset($data['state'])) {
            $this->state = 'ERROR';

            return array(
                'state' => 'FAILED',
                'error' => 'Device state is required'
            );
        }

        $this->state = 'RUNNING';

        $output = array(
            'device_id' => $expression['target'],
            'state' => $data['state'],
            'properties' => array(
                'speed' => isset($data['speed'])
                    ? $data['speed']
                    : null,
                'temperature' => isset($data['temperature'])
                    ? $data['temperature']
                    : null
            )
        );

        $this->state = 'READY';

        return array(
            'state' => 'SUCCESS',
            'format' => 'JSON',
            'output' => $output,
            'error' => null
        );
    }

    public function getState()
    {
        return $this->state;
    }
}

6.3 注册 Renderer

$rendererManager = new RendererManager();

$deviceStatusRenderer = new DeviceStatusRenderer();

$rendererManager->register(
    $deviceStatusRenderer
);

6.4 调用 Renderer

$expression = array(
    'id' => 3001,
    'type' => 'DEVICE_STATE',
    'target' => 'Motor_A',
    'data' => array(
        'state' => 'RUNNING',
        'speed' => 50,
        'temperature' => 65
    )
);

$result = $rendererManager->render(
    'device_status',
    $expression
);

得到:

RenderedResult
{
    state: "SUCCESS",
    format: "JSON",
    output: {
        device_id: "Motor_A",
        state: "RUNNING",
        properties: {
            speed: 50,
            temperature: 65
        }
    }
}

自定义 Renderer 与完整 SAI 流程

现在把第61~79章连接起来:

Decision
    ↓
Behavior
    ↓
Action
    ↓
ActionResult
    ↓
Expression
    ↓
SATE
    ↓
Template
    ↓
Custom Renderer
    ↓
Rendered Result
    ↓
Adapter
    ↓
External Environment

如果只是向外表现信息:

Expression
    ↓
SATE
    ↓
Custom Renderer
    ↓
Rendered Result
    ↓
Output

如果需要连接外部环境:

Rendered Result
    ↓
Adapter
    ↓
External System / Device

而外部环境返回:

Device / System
    ↓
Response
    ↓
Adapter
    ↓
Feedback
    ↓
Information
    ↓
Perception

于是形成:

Expression
    ↓
Renderer
    ↓
Adapter
    ↓
External Environment
    ↓
Feedback
    ↓
ICAI

Renderer 与 Adapter 的最终边界

这两个组件容易混淆,但职责完全不同:

Expression
    ↓
Renderer
    ↓
Rendered Result
    ↓
Adapter
    ↓
External Environment

Renderer:

“我要把数据表现成什么形式?”

Adapter:

“我要把这个结果连接到什么环境?”

例如:

Expression
    ↓
ApiRenderer
    ↓
JSON
    ↓
ApiAdapter
    ↓
External API

或者:

Expression
    ↓
DeviceRenderer
    ↓
Device Data
    ↓
DeviceAdapter
    ↓
Motor_A

所以:

Renderer = 表现转换
Adapter  = 环境连接

本章核心模型

RendererInterface
       ↓
Create Renderer
       ↓
Register
       ↓
RendererManager
       ↓
Expression
       ↓
Validate
       ↓
Supports Check
       ↓
Render
       ↓
RenderedResult
       ↓
Output / Adapter

完整扩展体系:

Extension
 ├── Custom Engine
 │      ↓
 │   EngineResult
 │
 ├── Custom Renderer
 │      ↓
 │   RenderedResult
 │
 └── Custom Adapter
        ↓
     External Environment

最终形成:

ICAI Core
    │
    ├── Engine
    │      └── 内部功能执行
    │
    ├── Renderer
    │      └── 表现形式转换
    │
    └── Adapter
           └── 外部环境连接

本章核心定义

Renderer Interface

Renderer Interface 是规定 Renderer 身份、版本、支持类型、表现转换和状态管理行为的统一接口。

Custom Renderer

自定义 Renderer 是按照 Renderer Interface 创建,用于将特定 Expression 按确定规则转换为指定表现格式的独立组件。

Rendered Result

Rendered Result 是 Renderer 对 Expression 完成表现转换后形成的结构化结果。

核心关系:

Expression
    ↓
Renderer
    ↓
Rendered Result

再与前面的 Adapter 连接:

Expression
    ↓
SATE
    ↓
Custom Renderer
    ↓
Rendered Result
    ↓
Custom Adapter
    ↓
External Environment

因此,第76~79章形成了一个完整的扩展体系:

Extension
   ├── Engine
   │     → 执行内部功能
   │
   ├── Renderer
   │     → 转换外部表现
   │
   └── Adapter
         → 连接外部环境

三者互不替代,分别解决:

Engine    = 怎么处理
Renderer  = 怎么表现
Adapter   = 怎么连接

这使 ICAI 可以在保持核心结构稳定的情况下,通过标准接口不断增加内部处理能力、表现能力和外部连接能力

Leave a Reply

Your email address will not be published. Required fields are marked *