【发布时间】:2020-12-22 19:28:58
【问题描述】:
我创建了以下对象工厂来实例化我所有接口的实现:
interface SomeInterface {
get(): string;
}
class Implementation implements SomeInterface {
constructor() {}
get() {
return "Hey :D";
}
}
type Injectable = {
[key: string]: () => unknown;
};
// deno-lint-ignore prefer-const
let DEFAULT_IMPLEMENTATIONS: Injectable = {
SomeInterface: () => new Implementation(),
};
let MOCK_IMPLEMENTATIONS: Injectable = {};
class Factory {
static getInstance(interfaceName: string, parameters: unknown = []) {
if (MOCK_IMPLEMENTATIONS[interfaceName])
return MOCK_IMPLEMENTATIONS[interfaceName]();
return DEFAULT_IMPLEMENTATIONS[interfaceName]();
}
static mockWithInstance(interfaceName: string, mock: unknown) {
MOCK_IMPLEMENTATIONS[interfaceName] = () => mock;
}
}
export const ObjectFactory = {
getInstance<T>(name: string): T {
return Factory.getInstance(name) as T;
},
mockWithInstance: Factory.mockWithInstance,
};
const impl = ObjectFactory.getInstance<SomeInterface>("SomeInterface");
如您所见,这个工厂允许您实例化和模拟这些接口。主要问题是我必须使用接口的名称和接口调用此函数以将类型保留在分配中:
ObjectFactory.getInstance<SomeInterface>("SomeInterface")
我见过this question,但我不喜欢使用Base 接口的想法。此外,这种方法也不保留类型。
理想情况下,我想使用我的方法,但不必使用接口,即只使用接口的名称。
旁注:Injectable 的声明是使该代码工作的一种技巧,理想情况下,我希望能够仅使用实现名称,即:
let DEFAULT_IMPLEMENTATIONS = {
SomeInterface: Implementation
}
【问题讨论】:
-
是编译时已知的接口列表吗?或者你会随着时间的推移添加新的?我希望这里的代码是minimal reproducible example,其中唯一存在的问题是您要询问的问题,其中一些行显示了预期与实际的行为。现在为了解决这个问题,我必须处理
ConcreteImplementation的任何内容,而且我没有在代码中看到用例。 -
我已经编辑了示例,如果您需要更多信息,我已经减少了我的大学项目中的用例,我试图使用干净的架构创建解析器:github.com/antoniogamiz/manga-api/blob/master/src/modules/…。
-
你可以使用this之类的断言函数来“动态地”将接口添加到列表中,但它比使用固定列表更复杂和脆弱
-
这些编辑使事情worse,因为它们有语法错误(大括号无效)和其他问题(
new Implementation()不是有效的() => unknown,没有名为getInstance()的函数)。请考虑将示例代码放入 IDE 并在发布之前测试其行为。我现在必须退出,但我的问题仍然存在:您是否需要能够通过mockWithInstance()来添加 接口,还是只使用现有接口的固定列表?前者在断言函数中是可能的,但后者更容易。 -
抱歉,现在已修复。是的,我使用现有接口的固定列表。我导入它们并像 SomeInterface 一样添加它们。
标签: typescript design-patterns factory