客户端打字稿:如何从工厂方法模式中删除循环依赖?

Client-side typescript: how do I remove circular dependencies from the factory method pattern?

我正在使用 factory method pattern in some of my code. The problem is, some of those instances also use the same factory method pattern. This creates circular dependencies and I can't think of a way of removing them. Let me give an example:

// factoryMethod.ts
import Instance1 from './Instance1';
import Instance2 from './Instance2';
import Instance3 from './Instance3';
import { Instance, InstanceName } from './Instance';

export const getInstanceByName = (
  instanceName: InstanceName
): Instance => {
  switch (instanceName) {
    case 'Instance1':
      return Instance1;
    case 'Instance2':
      return Instance2;
    case 'Instance3':
      return Instance3;
    default:
      throw new Error();
  }
};

// extremelyHelpfulUtilityFunction.ts
import { getInstanceByName } from './factoryMethod';

export const extremelyHelpfulUtilityFunction = (instanceName: InstanceName): number => {
  // Imagine this was an extremely helpful utility function
  return getInstanceByName(instanceName).num
}

// Instance.ts
export interface Instance {
  doSomething: () => number;
  num: number;
}

export type InstanceName = 'Instance1' | 'Instance2' | 'Instance3';

// Instance1.ts
import { extremelyHelpfulUtilityFunction } from './extremelyHelpfulUtilityFunction';

const i: Instance = {
  doSomething: (): number => {
    return extremelyHelpfulUtilityFunction('Instance2') + extremelyHelpfulUtilityFunction('Instance3'); // circular dependency
  },
}
export default i;

// Other instances defined below, you get the idea.

我正在使用汇总将其转换为单个 JavaScript 文件,当我这样做时,它会警告我存在循环依赖。我想摆脱这个警告。我意识到代码仍然可以运行,但我不希望那里出现警告。我如何修改这段代码,使 InstanceX 可以在不循环依赖的情况下获取 InstanceY?

IMO 的问题是 extremelyHelpfulUtilityFunction 必须知道 getInstanceByName,而这个工厂的结果总是可以提前被调用者知道并且所需的值作为参数传递给助手。

我会求婚

// Instance1.ts
const instance1: Instance = {
  doSomething: (): number => {
    return (new Instance2()).toNum() + (new Instance3()).toNum()
  },
}

with toNum 在 Instance.ts 中定义并在其子 class 中覆盖,使用助手但使用适当的参数,例如

// Instance2.ts
const instance2: Instance = {
  doSomething: ...,
  toNum: (): number => {
    return extremelyHelpfulUtilityFunction(1234)
  }
}

如果你为 Instance2 而不是这个对象声明了一个合适的 class 而不是这个对象,你将使用 this.num 而不是 1234 的地方,比如

// Instance2.ts
class Instance2 extends Instance {
  num = 1234;
  doSomething: ...
  toNum(): number {
    return extremelyHelpfulUtilityFunction(this.num)
  }
}
export default new Instance2();