我对Typescript和NodeJS很新,我正在尝试使用工厂在运行时创建对象。
作为示例,以下对象具有属性类型Text,现在在运行时获取它,我想创建TextContainer的实例:
{
type: "Text",
name: "Title"
}
我的工厂看起来像这样:
import {BaseContainer} from "../Containers/BaseContainer";
import {TextContainer} from "../Containers/TextContainer";
/**
* Used to dynamically create objects with different container classes
* in runtime
*/
export class ContainerFactory {
// Object containing all class names and types
private dictionary: Object;
/**
* Initializes factory dictionary
*/
constructor() {
// Initialize dictionary with classes
this.dictionary = {
"default": BaseContainer,
"Text": TextContainer,
"TextContainer": TextContainer
}
}
/**
* Builds object depending on className
* @param className
* @param params
*/
build(className: string, params: Object) {
// Return new class of type className, if not found
// return object with class of set default class
return className in this.dictionary ? new this.dictionary[className](params) : new this.dictionary['default'];
}
}
问题出现在BaseContainer类中(由TextContainer扩展并将由此工厂中将出现的更多类扩展)我在函数中使用工厂,这里是循环依赖,因为在BaseContainer我导入ContainerFactory并在ContainerFactory中导入BaseContainer。
我需要BaseContainer中的工厂,因为我有一个树状的层次结构,容器有子容器,它们本身就是容器。
我很感激有关如何解决此问题的建议,或者如何折射我的代码以使其可靠地工作。 我搜索了类似的问题,但还没有找到解决方法。
我在TextContainer类中收到以下错误(扩展BaseContainer):
extendStatics(d, b);
^
TypeError: Object prototype may only be an Object or null: undefined
答案 0 :(得分:1)
此任务的更好解决方案是使用装饰器将类型名称映射到相应的构造函数。例如:
Decorator.ts:
export function Container(className: string)
{
return (target: any) =>
{
Meta.classNameToCtor[!!className ? className : target.name] = target;
};
}
Meta.ts:
export class Meta
{
public static classNameToCtor: {[key: string]: any} = {};
}
现在您需要做的就是装饰每个容器类,如下所示:
@Container("default")
export class BaseContainer {...}
在您的工厂中通过Meta
访问构造函数:
build(className: string, params: Object)
{
return className in Meta.classNameToCtor ? new Meta.classNameToCtor[className](params) : new Meta.classNameToCtor['default'];
}
这种方法完全杀死了导入依赖,并且使用起来更具可扩展性和优雅性。