3

如何使用 Inversify 完成部分属性注入?

假设我们有课

class MyClass {
    constructor(
        @inject(EXTERNAL_A) private externalA: ExternalClassA,
        private b: string
    ) {}
}

如果 b 的所有可能值在编译时都已知,我如何在其他类中使用这个 MyClass 和 inversify。所以,我只需要一个 MyClass 的实例b = "a"和另一个带有b = "b".

我目前找到的唯一解决方案是两个为此定义两个不同的绑定或使用工厂直接调用new MyClass.

在第一种情况下,我只需要写类似的东西

container.bind<MyClass>(CLASS_A).toConstantValue(
    new MyClass(container.get<ExternalClassA>(EXTERNAL_A), "a")
);

container.bind<MyClass>(CLASS_B).toConstantValue(
    new MyClass(container.get<ExternalClassA>(EXTERNAL_A), "b")
);

看起来很乱,没有解决下一个问题,工厂也没有解决。如果在这种情况下我有很深的对象层次结构,我需要通过这个手动对象构建链来构建它们。

这里最好的方法是什么?

带有星号的任务,是否可以通过用提供的单个依赖项替换相同的单个依赖项来解决某些依赖项树?就像,我们可以有类似的东西

 |-----B-----e
A|-----C-----e
 |-----D
 |-----e

e所以我不想用我构建的依赖来替换依赖。我怎样才能做到这一点?

4

2 回答 2

1

您可以使用 .将工厂绑定到您的 inversify 容器toFactory。请注意,您的工厂可以接受参数。

https://github.com/inversify/InversifyJS/blob/master/wiki/factory_injection.md

这是一个专门针对您的用例的示例。

container
    .bind<(b: string) => MyClass>("MyClassFactory")
    .toFactory<MyClass>((context: interfaces.Context) => {
      return (b: string) => {
        const classA = context.container.get<ExternalClassA>("EXTERNAL_A")

        return new MyClass(classA, b)
      }
    })

因此,我们将绑定到标识符"MyClassFactory"一个函数,该函数返回一个实例,MyClass具体取决于您传递给它的参数。

由于我们EXTERNAL_A通过 inversify 从容器中获取,我们并没有自己实例化它,所以我们不需要担心它本身有什么依赖关系。

要使用您的工厂...

@injectable()
class SomeClass {
  @inject("MyClassFactory") private myClassFactory!: (b: string) => MyClass

  someMethod() {
    const myClassA = this.myClassFactory('a')
    const myClassB = this.myClassFactory('b')
  }
} 

需要注意的一件事是,在问题中,您正在使用toConstantValue,因此您的类被构建并绑定为单例。我不知道这是不是故意的,但如果是这样,你仍然可以使用上面的工厂来做到这一点......

container.bind<MyClass>("CLASS_A").toDynamicValue((context: interfaces.Context) => { 
  const myClassFactory = context.container.get<(b: string) => MyClass>("MyClassFactory")
  return myClassFactory('a')
})

container.bind<MyClass>("CLASS_B").toDynamicValue((context: interfaces.Context) => { 
  const myClassFactory = context.container.get<(b: string) => MyClass>("MyClassFactory")
  return myClassFactory('b')
})

您也可以通过编程方式创建单例。如果你有一些{identifier: "CLASS_A", factoryArg: 'a'}类型对象的数组,你可以循环它并像上面那样创建动态值。

关于您的最后一个问题,我的回答现在可能太长了,但是请查看文档中的这一部分,它可能会有所帮助!https://github.com/inversify/InversifyJS/blob/master/wiki/recipes.md#overriding-bindings-on-unit-tests

于 2019-11-20T08:47:32.640 回答
0

你好,

恐怕没有完美的解决方案。在这种情况下,我通常使用带有setorsetup方法的工厂模式。

例子:

interface MyInterface {
     myPublicMethod();
}

type MyInterfaceFactoryA = () => MyInterface;
type MyInterfaceFactoryB = () => MyInterface;

class MyClass extends MyInterface {

     private b: string;

     constructor(
          @inject(EXTERNAL_A) private externalA: ExternalClassA,
     ) {}

     public setup(b: string): void {
          this.b = b;
     }

}

当您设置容器时,通常在 aContainerModule中,您需要执行以下操作:

 bind<MyClass>("MyClass").to(MyClass);

 container.bind<MyInterface>(CLASS_A).toConstantValue(
      const myClass = context.container.get<MyClass>("MyClass");
      return myClass.setup("a");
 );

 container.bind<MyInterface>(CLASS_B).toConstantValue(
     const myClass = context.container.get<MyClass>("MyClass");
     return myClass.setup("a");
 );

然后就使用它:

 class MyOtherClass {

      constructor(
          @inject(CLASS_A) private _myInterfaceInstanceA: MyInterface,
          @inject(CLASS_B) private _myInterfaceInstanceB: MyInterface) {

      }

 }

希望它可以帮助你。您可以在以下位置找到更多信息:https ://github.com/inversify/InversifyJS/issues/530

于 2018-07-05T14:06:01.933 回答