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

第169章 Service层设计

第169章 Service层设计

169.1 提出背景

在前面的章节中,WSaiOS-ICAI 已经建立了从 Individual、Object、Attribute 到 Capability、Method、Decision、Behavior、Action、Execution、Result、Feedback、Memory、Experience 等认知对象,并进一步通过 OOP 的继承、组合、关系和 Runtime 形成统一对象体系。

但是,仅有 Domain Object 还不能直接构成完整的软件运行系统。

Domain Object 负责描述对象是什么、具有什么属性、处于什么状态以及具有什么认知结构;Engine 负责执行特定的计算、规则判断、递推、状态转换或处理过程;而多个 Domain Object 与多个 Engine 往往需要按照一定业务流程被组织起来。

因此,在对象层与计算引擎层之间,需要建立一个明确的 Service层(Service Layer)

Service层不是新的认知对象,也不是简单的函数集合,而是一个负责组织领域对象、调用领域引擎、控制执行流程、处理结果并形成运行闭环的软件工程层。

其核心职责可以表示为:

Service=Domain Object Coordination+Engine Invocation+Process Control+Result HandlingService = Domain\ Object\ Coordination + Engine\ Invocation + Process\ Control + Result\ Handling

即:

Service = 领域对象协调 + Engine调用 + 流程控制 + 结果处理。

因此,Service层解决的核心问题不是“对象是什么”,也不是“算法怎么算”,而是:

当前系统为了完成一个明确任务,需要按照什么流程组织哪些对象,并调用哪些Engine。


169.2 Service定义

169.2.1 Service的基本定义

Service(服务) 是对一个完整系统操作过程进行组织和封装的软件对象,它接收明确的输入,通过协调一个或多个 Domain Object、Engine、Repository 或其他 Service,完成规定的处理流程,并返回结构化结果。

可以定义:

S=(I,D,E,P,R,St)S=(I,D,E,P,R,St)

其中:

  • SS:Service;
  • II:Input,输入;
  • DD:Domain Objects,参与处理的领域对象;
  • EE:Engine,需要调用的计算或处理引擎;
  • PP:Process,Service内部执行流程;
  • RR:Result,最终处理结果;
  • StSt:State,Service当前运行状态。

因此,一个Service并不是一个单独的算法。

它更接近:

Input→Load Domain→Check→Call Engine→Update Domain→Generate Result→Save→ReturnInput \rightarrow Load\ Domain \rightarrow Check \rightarrow Call\ Engine \rightarrow Update\ Domain \rightarrow Generate\ Result \rightarrow Save \rightarrow Return

例如:

GoalService
    ↓
读取Individual
    ↓
读取Goal
    ↓
读取Priority
    ↓
调用DecisionEngine
    ↓
生成Decision
    ↓
更新Goal状态
    ↓
保存Decision History
    ↓
返回Decision Result

Service负责把这些步骤组织起来。


169.2.2 Service不是Domain Object

Service与Domain Object存在根本区别。

Domain Object表示系统中的一个具有明确意义的对象。

例如:

Individual
Object
Capability
Method
Decision
Behavior
Action
Execution
Result
Feedback
Memory
Experience
Risk
Diagnosis
Repair

这些对象都有自己的数据、状态、关系和生命周期。

而Service表示:

围绕某一项系统职责,对多个对象进行组织和处理的运行单元。

例如:

CapabilityService
MethodService
DecisionService
BehaviorService
ExecutionService
FeedbackService
MemoryService
ExperienceService
DiagnosisService
RepairService

因此:

Domain Object=WhatDomain\ Object = What

而:

Service=How to organizeService = How\ to\ organize

Domain Object描述“是什么”。

Service描述“如何组织这些对象完成一次完整操作”。


169.3 Service职责

Service层必须具有明确边界。

不能把所有系统逻辑全部放入Service,也不能让Service承担Domain Object、Engine、Repository的全部职责。

Service的核心职责主要包括以下几个方面。

169.3.1 输入接收

Service首先接收外部请求或上层模块传入的结构化数据。

例如:

$input = array(
    'individual_id' => 1001,
    'goal_id' => 2001
);

Service对输入进行基本检查。

if (empty($input['individual_id'])) {
    return false;
}

Service可以进行流程级验证,但不应该把所有领域规则都写在这里。


169.3.2 Domain Object加载

Service需要根据当前任务获取相关Domain Object。

例如:

IndividualService
    ↓
Individual
    ↓
Capability[]
Method[]
Behavior[]
Memory[]
Experience[]

又例如DecisionService:

DecisionService
    ↓
Goal
Capability
Method[]
Condition[]
Experience[]
History

Service负责组织这些对象之间的使用关系。


169.3.3 Engine调用

Service并不应该自己承担所有复杂计算。

如果系统已经存在专门的Engine,则Service负责调用Engine。

例如:

DecisionService
        ↓
DecisionEngine
        ↓
Candidate Evaluation
        ↓
Decision Result

或者:

RiskService
        ↓
RiskEngine
        ↓
Risk Evaluation
        ↓
Risk Result

因此:

Service→EngineService \rightarrow Engine

是Service层非常重要的一条依赖关系。


169.3.4 流程控制

Service最重要的职责之一,是控制多个步骤的执行顺序。

例如执行一个Behavior:

BehaviorService
    ↓
Load Behavior
    ↓
Check Condition
    ↓
Load Actions
    ↓
Create Execution
    ↓
Execute Action
    ↓
Collect Result
    ↓
Generate Feedback
    ↓
Update State
    ↓
Store History

这里的每一步可能由不同对象或Engine完成。

Service负责将这些步骤组织成完整流程。

因此可以表示为:

PS={p1,p2,p3,…,pn}P_S = \{p_1,p_2,p_3,\ldots,p_n\}

其中:

  • PSP_S:Service Process;
  • pip_i:Service中的一个处理步骤。

169.3.5 状态控制

Service还负责管理一次服务执行过程的状态。

例如:

Created
   ↓
Initialized
   ↓
Ready
   ↓
Running
   ↓
Completed

异常情况下:

Running
   ↓
Failed
   ↓
Diagnosis
   ↓
Repair
   ↓
Retry

Service状态不能简单依靠“函数有没有返回值”判断。

必须结合实际执行结果。


169.3.6 Result处理

Engine产生计算结果,Domain Object产生状态变化,而Service需要将这些结果组织成上层可以使用的Service Result。

例如:

Engine Result
     ↓
Domain Update
     ↓
Service Result

Service Result可以包含:

array(
    'status' => 'completed',
    'result' => $result,
    'object_id' => $objectId,
    'state' => $state
);

因此:

Engine Result≠Service ResultEngine\ Result \neq Service\ Result

Engine Result是某个Engine的处理结果。

Service Result是一次完整Service调用的最终结果。


169.4 Service与Domain Object

169.4.1 基本关系

Service与Domain Object之间主要是 使用与协调关系

可以表示为:

Service→Domain ObjectService \rightarrow Domain\ Object

例如:

DecisionService
    ↓
Goal
Capability
Method
Candidate
Condition
Experience
Decision

Service不应该取代这些Domain Object。

例如,不应该设计成:

class DecisionService
{
    protected $goal;
    protected $capability;
    protected $method;
    protected $memory;
    protected $experience;
    protected $decision;
}

然后把所有领域数据都塞进Service。

更合理的方式是:

class DecisionService
{
    public function decide($input)
    {
        // Load Domain Objects
        // Coordinate Engine
        // Create Decision
        // Return Result
    }
}

Domain Object保持自己的职责。


169.4.2 Service不拥有全部Domain逻辑

例如Capability的条件判断属于Capability领域逻辑:

Capability
    ↓
Condition
    ↓
Range
    ↓
State
    ↓
Verification

Service只负责调用:

$available = $capability->isAvailable();

而不是在Service中重新写:

if ($type && $condition && $range && $state && $verification) {
    ...
}

否则会造成Domain Logic泄漏。

因此应遵循:

属于Domain Object本身的规则,应尽量保留在Domain Object或Domain Engine中。

Service主要负责组织。


169.5 Service与Engine

169.5.1 Engine定义

在WSaiOS-ICAI中,Engine可以定义为:

Engine(引擎)是负责执行特定计算、规则处理、递推、判断、匹配、状态转换或其他确定性处理过程的核心计算对象。

例如:

RuleEngine
DecisionEngine
CapabilityEngine
MethodEngine
StateEngine
RiskEngine
DiagnosisEngine
MemoryEngine
ExperienceEngine
VerificationEngine

Engine强调:

怎么计算、怎么判断、怎么处理。

Service强调:

什么时候调用、调用谁、调用顺序是什么、结果如何组织。


169.5.2 Service与Engine的职责边界

二者可以通过以下方式区分:

对象 核心职责
Domain Object 描述领域对象
Service 组织完整业务/认知流程
Engine 执行特定计算或规则
Repository 数据持久化
Controller 接收外部请求
Manager 管理对象集合或系统资源

因此:

Controller→Service→Engine→Domain ObjectController \rightarrow Service \rightarrow Engine \rightarrow Domain\ Object

但实际工程中并不是严格的单向关系,Service也可能先加载Domain Object,再调用Engine:

Controller→Service→Repository→Domain ObjectController \rightarrow Service \rightarrow Repository \rightarrow Domain\ Object

然后:

Service→EngineService \rightarrow Engine

最终:

Engine→Domain Object→ResultEngine \rightarrow Domain\ Object \rightarrow Result


169.6 Service的典型执行模型

一个完整Service可以抽象为:

S=(I→L→V→E→U→R→P)S= (I \rightarrow L \rightarrow V \rightarrow E \rightarrow U \rightarrow R \rightarrow P)

其中:

  • II:Input;
  • LL:Load;
  • VV:Validation;
  • EE:Engine Execution;
  • UU:Update;
  • RR:Result;
  • PP:Persistence。

即:

Input
 ↓
Load
 ↓
Validation
 ↓
Engine
 ↓
Domain Update
 ↓
Result
 ↓
Persistence

例如DecisionService:

Decision Input
      ↓
Load Goal
      ↓
Load Candidate Methods
      ↓
Load Conditions
      ↓
Load Experience
      ↓
DecisionEngine
      ↓
Candidate Evaluation
      ↓
Candidate Selection
      ↓
Create Decision
      ↓
Save Decision
      ↓
Decision Result

这里真正的Decision逻辑仍属于Decision Object与DecisionEngine,而Service负责把完整过程串联起来。


169.7 Service的PHP OOP结构

Service可以采用独立的PHP类。

例如:

class DecisionService
{
    protected $decisionEngine;
    protected $decisionRepository;
    protected $goalRepository;
    protected $methodRepository;

    public function __construct(
        $decisionEngine,
        $decisionRepository,
        $goalRepository,
        $methodRepository
    ) {
        $this->decisionEngine = $decisionEngine;
        $this->decisionRepository = $decisionRepository;
        $this->goalRepository = $goalRepository;
        $this->methodRepository = $methodRepository;
    }

    public function decide($input)
    {
        $goal = $this->goalRepository->find(
            $input['goal_id']
        );

        $methods = $this->methodRepository->findByGoal(
            $goal->getId()
        );

        $result = $this->decisionEngine->evaluate(
            $goal,
            $methods
        );

        return $result;
    }
}

这里有几个重要边界。

DecisionService不负责:

数据库SQL细节

因为数据库操作属于Repository。

也不负责:

候选方案评分算法

因为这是DecisionEngine的职责。

更不应该负责:

定义Decision对象所有领域属性

因为这是Domain Object的职责。

因此形成:

DecisionService
    ├── GoalRepository
    ├── MethodRepository
    ├── DecisionEngine
    └── DecisionRepository

169.8 Service与Manager的区别

WSaiOS-ICAI工程中还需要区分Service和Manager。

Manager通常强调:

对象、资源、集合和生命周期管理。

Service强调:

一次完整任务或操作流程。

例如:

CapabilityManager

负责:

Capability创建
Capability加载
Capability注册
Capability更新
Capability删除
Capability集合管理

而:

CapabilityService

负责:

接收任务
 ↓
加载Capability
 ↓
检查Condition
 ↓
调用CapabilityEngine
 ↓
执行Verification
 ↓
生成Capability Result

因此:

Manager=Object/Resource ManagementManager = Object/Resource\ Management

而:

Service=Process OrchestrationService = Process\ Orchestration

二者可以同时存在。


169.9 Service生命周期

Service本身也具有生命周期。

可以定义:

SL=Created→Initialized→Ready→Running→CompletedSL= Created \rightarrow Initialized \rightarrow Ready \rightarrow Running \rightarrow Completed

异常情况:

Running→Failed→Diagnosed→Recovered→ReadyRunning \rightarrow Failed \rightarrow Diagnosed \rightarrow Recovered \rightarrow Ready

完整生命周期为:

Created
   ↓
Initialized
   ↓
Ready
   ↓
Running
   ↓
Processing
   ↓
Result Generated
   ↓
Completed

失败路径:

Running
   ↓
Failed
   ↓
Diagnosis
   ↓
Repair
   ↓
Verification
   ↓
Retry / Completed

169.9.1 Created

Service对象被实例化。

$service = new DecisionService(
    $decisionEngine,
    $decisionRepository,
    $goalRepository,
    $methodRepository
);

此时只是Service对象存在。

并不意味着Service已经执行。


169.9.2 Initialized

Service完成依赖对象初始化。

例如:

DecisionEngine
DecisionRepository
GoalRepository
MethodRepository

全部已经可用。


169.9.3 Ready

Service进入可执行状态。

此时:

Dependencies = Available
Configuration = Valid
Required Resources = Available

Service可以接受任务。


169.9.4 Running

Service开始执行具体任务。

例如:

$result = $service->decide($input);

此时Service进入Running。


169.9.5 Completed

只有当完整流程实际完成,并得到有效Result时,Service才能进入Completed。

因此:

Function Returned

并不一定等于:

Service Completed

必须根据实际Result判断。


169.9.6 Failed

当执行过程中发生无法完成的情况时:

Running → Failed

例如:

Domain Object不存在
Engine执行失败
Required Condition不满足
数据保存失败
Verification失败

失败必须作为合法状态保存,而不能被程序简单隐藏。


169.10 Service状态模型

可以建立统一Service State:

CREATED
INITIALIZED
READY
RUNNING
COMPLETED
FAILED
CANCELLED
BLOCKED

对应PHP:

class ServiceState
{
    const CREATED = 'created';
    const INITIALIZED = 'initialized';
    const READY = 'ready';
    const RUNNING = 'running';
    const COMPLETED = 'completed';
    const FAILED = 'failed';
    const CANCELLED = 'cancelled';
    const BLOCKED = 'blocked';
}

状态转换必须受到规则控制。

例如:

CREATED → INITIALIZED
INITIALIZED → READY
READY → RUNNING
RUNNING → COMPLETED
RUNNING → FAILED
RUNNING → CANCELLED
READY → BLOCKED

不能允许任意状态直接跳转。

例如:

CREATED → COMPLETED

如果没有经过实际初始化和执行,则不应直接认为Service已经完成。


169.11 Service与Repository

Service通常需要通过Repository取得和保存Domain Object。

因此:

Service→RepositoryService \rightarrow Repository

例如:

$goal = $this->goalRepository->find($goalId);

Service不应该直接操作数据库:

mysql_query(...);

也不应该在Service中大量出现SQL。

数据库属于Persistence层。

因此形成:

Service
   ↓
Repository
   ↓
MySQL

读取:

MySQL
   ↓
Repository
   ↓
Domain Object
   ↓
Service

保存:

Domain Object
   ↓
Service
   ↓
Repository
   ↓
MySQL

这样可以保持认知对象与数据库之间的边界。


169.12 Service层与ICAI认知流程

Service层最终需要服务于前面已经建立的ICAI认知流程。

例如完整决策过程:

Need
 ↓
Goal
 ↓
Capability
 ↓
Method Candidates
 ↓
Decision
 ↓
Behavior
 ↓
Action
 ↓
Execution
 ↓
Result
 ↓
Feedback
 ↓
Memory
 ↓
Experience

在工程中可以进一步映射为:

NeedService
 ↓
GoalService
 ↓
CapabilityService
 ↓
MethodService
 ↓
DecisionService
 ↓
BehaviorService
 ↓
ExecutionService
 ↓
FeedbackService
 ↓
MemoryService
 ↓
ExperienceService

这些Service并不是新的认知对象。

它们是:

将Domain Object和Engine组织成完整运行流程的工程服务层。


169.13 Service之间的协作

Service之间可以形成明确的调用链。

例如:

DecisionService
      ↓
BehaviorService
      ↓
ExecutionService
      ↓
FeedbackService
      ↓
MemoryService
      ↓
ExperienceService

一次完整行为执行可以表示为:

DecisionService→BehaviorService→ExecutionService→FeedbackService→MemoryService→ExperienceServiceDecisionService \rightarrow BehaviorService \rightarrow ExecutionService \rightarrow FeedbackService \rightarrow MemoryService \rightarrow ExperienceService

最终:

Experience
      ↓
Decision

形成闭环。

但Service之间不能无限相互调用,否则容易产生循环依赖。

因此需要保持职责边界。

例如:

DecisionService

负责决策。

ExecutionService

负责执行。

FeedbackService

负责反馈处理。

不应该让:

ExecutionService

直接承担完整Decision逻辑。


169.14 Service与Engine的完整工程结构

一个较完整的WSaiOS-ICAI模块可以设计为:

Controller
    ↓
Service
    ├── Repository
    │      ↓
    │   Domain Object
    │
    ├── Engine
    │      ↓
    │   Calculation / Rule
    │
    └── Repository
           ↓
        Persistence

进一步形成:

┌──────────────────────────────┐
│         Controller           │
│     External Request         │
└──────────────┬───────────────┘
               ↓
┌──────────────────────────────┐
│           Service            │
│  Process / Coordination      │
└───────┬──────────────┬───────┘
        ↓              ↓
┌──────────────┐ ┌──────────────┐
│ Domain Object│ │    Engine    │
│ What         │ │ How Compute  │
└──────┬───────┘ └──────┬───────┘
       ↓                 ↓
       └────────┬────────┘
                ↓
             Result
                ↓
           Repository
                ↓
              MySQL

该结构将对象、计算、流程和持久化进行了明确分离。


169.15 Service不是“大脑”

在ICAI工程中必须特别注意:

Service不是“大脑”。

Service不能承担所有认知能力。

它只是运行组织层。

真正的认知结构来自:

Object
Knowledge
Capability
Method
Decision
Behavior
Memory
Experience
Rule
State
Relation

真正的计算由:

Engine

完成。

Service只是:

组织
调用
协调
控制
更新
返回

因此:

ICAI≠ServiceICAI \neq Service

而:

ICAI System=Domain Objects+Rules+Engines+Services+Persistence+RuntimeICAI\ System = Domain\ Objects + Rules + Engines + Services + Persistence + Runtime


169.16 Service的工程原则

Service层应遵循以下原则。

第一,单一职责

一个Service应该围绕一个明确的系统职责建立。

例如:

DecisionService

负责Decision流程,而不是同时负责Memory、Repair、Risk全部流程。

第二,领域逻辑归Domain

属于Domain Object的规则尽量放入Domain Object或Domain Engine。

第三,计算归Engine

复杂判断、递推、规则计算、状态计算等,应由对应Engine完成。

第四,数据访问归Repository

Service不直接承担MySQL细节。

第五,流程归Service

跨多个Domain Object的完整处理流程由Service组织。

第六,状态必须真实

Service状态必须由实际执行过程产生,不能人为标记为Completed。

第七,失败必须保留

Service失败是正常工程状态。

Failed

不是异常情况下必须隐藏的数据。

失败结果可以继续进入:

Diagnosis
→
Repair
→
Verification

从而形成系统恢复闭环。


169.17 Service层与前面OOP体系的统一

第166章建立了:

Individual→InheritanceIndividual \rightarrow Inheritance

第167章建立了:

Individual→CompositionIndividual \rightarrow Composition

第168章建立了:

Class→Object→RuntimeClass \rightarrow Object \rightarrow Runtime

第169章进一步增加:

Runtime→Service→Engine→Domain ObjectRuntime \rightarrow Service \rightarrow Engine \rightarrow Domain\ Object

因此,WSaiOS-ICAI的软件对象体系可以进一步表示为:

Class
 ↓
Object
 ↓
Runtime Object
 ↓
Service
 ↓
Domain Object
 ↓
Engine
 ↓
Execution
 ↓
Result
 ↓
Feedback
 ↓
Memory
 ↓
Experience

其中Service是运行组织层。


169.18 Service统一模型

经过本章定义,可以建立Service统一模型:

S=(I,D,E,P,R,St,L)S=(I,D,E,P,R,St,L)

其中:

  • II:Input,输入;
  • DD:Domain Objects,领域对象;
  • EE:Engines,计算引擎;
  • PP:Process,服务流程;
  • RR:Result,服务结果;
  • StSt:State,服务状态;
  • LL:Lifecycle,服务生命周期。

其基本运行关系为:

Input→Domain Load→Validation→Engine→Domain Update→Result→PersistenceInput \rightarrow Domain\ Load \rightarrow Validation \rightarrow Engine \rightarrow Domain\ Update \rightarrow Result \rightarrow Persistence

生命周期为:

Created→Initialized→Ready→Running→CompletedCreated \rightarrow Initialized \rightarrow Ready \rightarrow Running \rightarrow Completed

失败路径为:

Running→Failed→Diagnosis→Repair→Verification→RetryRunning \rightarrow Failed \rightarrow Diagnosis \rightarrow Repair \rightarrow Verification \rightarrow Retry


169.19 本章小结

Service层解决的是ICAI工程中一个非常关键的问题:

如何把已经建立的Domain Object、Engine、Repository和Runtime组织成可以实际运行的完整流程。

Domain Object负责描述:

是什么

Engine负责处理:

怎么算

Repository负责:

怎么保存和读取

Service负责:

怎么组织这些对象完成一次完整任务

因此:

Domain Object=WhatDomain\ Object = What Engine=How to ComputeEngine = How\ to\ Compute Repository=How to PersistRepository = How\ to\ Persist Service=How to OrchestrateService = How\ to\ Orchestrate

在WSaiOS-ICAI中,Service不应该被设计成新的“大脑”,也不应该成为包含所有业务代码的巨大类,而应该成为一个具有明确职责、明确输入、明确依赖、明确状态、明确生命周期和明确Result的工程运行层。

最终形成:

ICAI Engineering=Object+Composition+Relation+Runtime+Domain+Engine+Service+Repository\boxed{ ICAI\ Engineering = Object + Composition + Relation + Runtime + Domain + Engine + Service + Repository }

进一步进入实际运行过程:

Goal→Capability→Method→Decision→Service→Engine→Behavior→Action→Execution→Result→Feedback→Memory→Experience\boxed{ Goal \rightarrow Capability \rightarrow Method \rightarrow Decision \rightarrow Service \rightarrow Engine \rightarrow Behavior \rightarrow Action \rightarrow Execution \rightarrow Result \rightarrow Feedback \rightarrow Memory \rightarrow Experience }

由此,前面建立的ICAI对象理论开始真正进入 MVC、OOP、Service、Engine、Repository和Runtime组成的软件工程实现层

第169章完成的是“流程组织层”的定义。下一阶段如果继续向工程内核推进,需要进一步解决Service如何统一管理事务、上下文、状态、异常、Result以及Service之间的依赖关系,从而形成可运行的 ICAI Application Service与Runtime Service体系

Leave a Reply

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