一、问题提出
基于虚幻引擎开发数字孪生城市平台,需要定制开发开放的、持续进化的二次开发接口,我们可能面临的开发效率、系统稳定性的挑战需要我们认真考虑以下几个方面的问题:
1、如何避免底层对象、函数修改后开发人员花大量时间维护、反复修改接口映射逻辑
对于接口映射,最简单的逻辑就是通过具有“掌控一切”的“上帝之手”来控制所有的调用过程,这种实现的逻辑对于小型系统来说还是可以接受的,但对于相对较大的系统其灾难性是显而易见的。可以设想如果系统有成百上千个接口,映射到底层数百个对象,对这些映射进行维护无疑需要维护者具有“美女绣花”般的精细和耐心,而且一旦底层架构进行调整,整个逻辑几乎需要推倒重来,这显然不是一个良好的产品所应该采用的架构。
2、如何让外部接口相对高效率地映射到底层,尽可能降低开发人员处理工作量和出错概率
外部接口到底层的映射本质上是体力活,没有太高的技术含量,但是一不小心就容易出错,需要头脑十分清醒和细心,应尽可能简化映射规则和操作流程,降低开发人员维护映射的负担。同时,如果函数调用设计结构体、数组类型的参数的传递处理起来是比较费力并容易出错的,需要对这类结构进行自动化处理。
3、如何确保数据接口、传输流程的规范,避免开发过程随意性造成传输调用逻辑的混乱
由于接口映射技术性不是很强,开发人员在开发过程中往往容易产生一定的随意性,有时候为了减少开发时间往往会下意识走捷径,不考虑传输数据的完整性和多元化的应用场景,这很可能会造成系统在一些场景下可用,切换应用场景后就会出问题。作为平台化产品,为了降低此类风险,需要建立规则以及确保规则得以严格执行的机制。
二、核心思路
针对以上三点主要的问题,我们考虑设计一套具有一定通用性、能够适应绝大多数接口调用场景的的命令传输框架,其核心思想如下:
1、摒弃“上帝之手”主控模式,采用注册制,由有能力处理相关命令对象注册,当对象不在具备相关能力时,只要简单地取消注册即可,不需要对映射逻辑进行任何修改。进一步,如果在不同的接口调用场景下,同一个命令需要采用不同对象调用,只要对象根据环境上下文决定是否注册或注销即可。
2、在框架内实现对Json命令、字符命令的自动解析,支持数组、结构体等复杂接口,开发人员不必在映射接口考虑如何解析相关的命令和消息,极大降低接口映射维护工作量,避免由于工作疲劳造成的失误推升产品研发成本。
3、定义命令、消息传输的标准接口,在流程中对接口规范性进行验证,避免开发随意性。
三、框架设计
框架主要由命令消息接口、命令处理泵(CommandPump)、命令处理任务队列(CommandProcessTask)、命令处理代理(CommandProcessorProxy)构成。
3.1 消息接口
消息接口包括ICommandExcutor、IMessageReceiver和ICommandCaller;ICommandExcutor定义了命令执行者必须实现的接口,主要接口方法包括GetSupportCmdTypes、RegisterExecutor、UnRegisterExecutor、Excute,用于注册执行者所能够执行的命令,以及用于CommandPunp调用的命令执行接口。
ICommandCaller为命令执行回调接口,用于传送命名执行结果返回值;
IMessageReceiver为消息接收接口,用于接收各类事件,包括场景变化、数据处理、数据加载启动、过程和结果消息的传输。
3.2 CommandPump
命令传输泵CommandPump是命令传输的核心类,用于管理所有命令执行者和消息接收者,根据命令代码快速找到执行者并执行相关命令。
TArray<ICommandExcutor *> FindExecutors;
CommandExecutors.MultiFind(Cmd->CommandType,FindExecutors);
for (ICommandExcutor* Executor : FindExecutors)
{
FDCRCommandMessage* CmdMsg=Executor->Excute(Cmd);
}
3.2 命令处理代理
命令处理代理是底层实现和上层接口之间的交付代理,实现将上层命令进行解析并按底层接口规范发给CommanPump,同时将CommandPunp接收底层的消息转发给代理,代理再解析成上层接口能够解析的格式发送给上层应用。
四、 主要流程
4.1 注册、注销流程
4.2 命令执行流程
4.3 命令代理处理流程
五、 难点技术解决
51 可复用的命令、消息快速注册、注销机制
5.2 复杂多层结构命名、消息的全通用解析
5.3 命令消息的同步调用和异步调用支持
未完待续......