对“是否有任何标准或公认方式来做这样的事情?”的简短回答?应该是:没有。
这主要是因为您根本不希望您的 UI 知道此类信息。您希望您的 UI 成为您的 UI。一旦你的 UI 开始根据它是处于“测试模式”还是“生产模式”做出一些决定,你就会走上一个滑坡,最终将导致噩梦般的代码库。
这并不意味着您的问题无法解决;只是应该以不同的方式处理解决方案。我将首先解释一般原则,不涉及任何语言细节,然后提供一些 javascript 指南。
一般原则
您为此苦苦挣扎的唯一原因是您的 UI 与 API 的耦合过于紧密。
解决方案恰好与您希望使用模拟的任何情况完全相同。
- 编程到接口,而不是实现。 (确保您的 UI 仅绑定到 API 的抽象,而不是“真正/生产 API”。)
- 将实例化与交互分开。 (不要让您的 UI 创建其任何 API 依赖项,因为这会将其绑定到特定的实现 - 而是在 UI 上提供接口,以便为其提供应该使用的特定 API 实例。)
编程到接口
首先请注意,上述短语并不意味着您的语言需要支持“interface”结构。 (这只是一些语言实现者对名称的不幸选择。)
- 定义一个基类/对象,它定义了您的 API 应该支持的每个方法/消息。 (但是,这些实际上都不会在基类/对象上实现。)
- 您的 UI 应该有一个对 APIInterface 的变量/字段/引用。
- 您的 UI 将通过接口引用从 API 调用它需要的方法。例如。
APIRef.DoMethod1(...) 或 APIRef->DoMethod1(...) 或 [APIRef DoMethod1:...] 等
将实例化与交互分开
这里要避免的是:
CreateUI {
APIRef = CreateAPI;
}
以上内容将您的 UI 绑定到特定实现,并强制您在 UI 代码中包含这些文件/依赖项。您宁愿让您的 UI 被告知要使用哪个 API。例如
CreateUI(APIInterface APIToUse) { //NB: Notice that the type use to refer
//to the API is the abstract base type
//defined earlier (keeping to the "Program
//to an interface" principle).
APIRef = APIToUse;
}
//or
SetAPI(APIInterface APIToUse) {
APIRef = APIToUse;
}
现在您的生产应用程序可能如下所示:
API = CreateTrueAPI;
UI = CreateUI(API);
而您的测试应用程序可能看起来像这样:
API = CreateMockAPI;
UI = CreateUI(API);
请注意,使用此解决方案时,您的 UI 不知道“测试模式”或“生产模式”。它只是使用它提供的 API。唯一知道“测试模式”(从某种意义上说)和模拟 API 是测试应用程序。
将这些原则应用于 Javascript
首先声明一下:虽然我熟悉Javascript的语言原理,但是我从来没有做过JS开发。所以可能会出现一些无法预料的并发症。不过,在最坏的情况下,只要稍加调整和研究,我相信你会想出办法的。
Javascript 支持鸭子类型,这基本上意味着您可以向任何对象发送任何消息,并且在运行时对象将决定它是否可以实际处理该消息。您会在编译时检查您没有犯任何拼写错误,但据我了解:您根本不需要定义抽象基接口。
所以...
- 只需确保您的 UI 具有对 API 对象的引用。
- 确保您的 UI 不包含任何 API 实现文件(无论是真实/生产版本还是模拟版本)。
- 在您的生产主机中创建真正的 API,创建 UI 并将真正的 API 传递给 UI。
- 在您的测试主机中创建模拟 API,创建 UI 并将模拟 API 传递给 UI。