第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体系。