因导入引发的循环依赖问题:含容器实体的实体工厂架构
解决ContainerEntity与EntityFactory的循环依赖问题
问题背景
现有架构包含:
- 抽象类
AbstractEntity - 实体生成工厂
EntityFactory - 多个继承自
AbstractEntity的实体类
新增可包含实体列表的ContainerEntity后,出现循环依赖警告,相关代码示例如下:
抽象类定义
// abstract/entity.ts export abstract class AbstractEntity { readonly id: IdKey; }
普通实体类
// entities/concrete-entity.ts export class ConcreteEntity extends AbstractEntity { readonly type = 'concrete type'; } // entities/concrete-entity2.ts export class ConcreteEntity2 extends AbstractEntity { readonly type = 'concrete type2'; }
实体工厂类
// abstract/factory.ts export abstract class EntityFactory { static create(creationCase): AbstractEntity | null { if (creationCase === 'someCase') { return new ConcreteEntity(); } if (creationCase === 'otherCase') { return new ConcreteEntity2(); } if (creationCase === 'containerCase') { return new ContainerEntity(); } return null; } static createFromArray(creationCases): AbstractEntity[] { return creationCases.map(this.create); } }
出现问题的ContainerEntity
// entities/container-entity.ts export class ContainerEntity extends AbstractEntity { readonly type = 'container'; readonly entities: AbstractEntity[] = EntityFactory.createFromArray(creationCases); }
循环依赖原因
EntityFactory导入ContainerEntity用于创建容器实例ContainerEntity导入EntityFactory用于初始化内部的实体列表
可行解决方案
方案1:延迟初始化容器内的实体列表
将实体列表的初始化逻辑从类属性定义移到构造函数中,通过动态导入规避编译时的循环依赖:
// entities/container-entity.ts export class ContainerEntity extends AbstractEntity { readonly type = 'container'; readonly entities: AbstractEntity[]; constructor(private creationCases) { super(); // 异步初始化实体列表 (async () => { const { EntityFactory } = await import('../abstract/factory'); this.entities = EntityFactory.createFromArray(creationCases); })(); } }
注意:此方式下entities为异步初始化属性,若需同步使用需调整调用逻辑。
方案2:拆分工厂职责
单独创建ContainerFactory负责容器实体的创建,分离通用实体与容器实体的创建逻辑,避免互相依赖:
// abstract/container-factory.ts import { ContainerEntity } from '../entities/container-entity'; import { EntityFactory } from './factory'; export abstract class ContainerFactory { static createContainer(creationCases): ContainerEntity { const container = new ContainerEntity(); container.entities = EntityFactory.createFromArray(creationCases); return container; } }
修改EntityFactory,移除对ContainerEntity的直接导入,改为调用ContainerFactory:
// abstract/factory.ts import { ContainerFactory } from './container-factory'; export abstract class EntityFactory { static create(creationCase): AbstractEntity | null { if (creationCase === 'someCase') { return new ConcreteEntity(); } if (creationCase === 'otherCase') { return new ConcreteEntity2(); } if (creationCase === 'containerCase') { return ContainerFactory.createContainer([]); } return null; } static createFromArray(creationCases): AbstractEntity[] { return creationCases.map(this.create); } }
同步修改ContainerEntity,不再直接依赖EntityFactory:
// entities/container-entity.ts export class ContainerEntity extends AbstractEntity { readonly type = 'container'; entities: AbstractEntity[] = []; // 由外部工厂负责填充 }
方案3:使用依赖注入容器
若项目规模较大,可引入依赖注入容器(如TypeDI),通过容器管理实体与工厂的实例,彻底消除直接导入依赖:
- 为所有实体和工厂添加DI装饰器
- 在需要创建实例时,通过DI容器获取实例,而非直接导入类
内容的提问来源于stack exchange,提问作者IamCracker
相关产品推荐
相关产品推荐

