Factory with parameters in InversifyJS

浪尽此生 提交于 2020-06-27 14:36:10

问题


I'm using InversifyJS with TypeScript.

Let's say I have a class which has a mixture of injected and non-injected constructor parameters:

@injectable()
export class MyClass {
    constructor(
      foo: Foo, // This thing isn't injectable
      @inject(Bar) bar: Bar // This thing is
   ){
      ...
   }
}

I would like to inject a factory for this class into some other class and then invoke it with a value for the first parameter.

@injectable()
export class SomeOtherClass {
   constructor(
      @inject("Factory<MyClass>") myClassFactory: (foo: Foo) => MyClass
   ){
      const someFoo = new Foo();
      const myClass = myClassFactory(someFoo);
   }
}

My question: is there some auto-magic in Inversify that will allow me to inject this factory?

The best I've come up with so far is this:

bind<interfaces.Factory<MyClass>>("Factory<MyClass>").toFactory(context =>
    (foo: Foo) => 
        new MyClass(foo, context.kernel.get<Bar>(Bar))
);

But that means I'm explicitly new()-ing MyClass and every new injectable dependency of MyClass has to be added here too.

Is there a better way? Perhaps something based on parameter names like Ninject Factory Extensions?


回答1:


I'm the author of InversifyJS. I don't think there is a problem about using new inside the factory, remember that the job of the factory is to create a new instance.

It is true that calling container.get<T> multiple times inside a factory is not a good thing.

I can suggest breaking the initialization of MyClass into to phases:

The class instantiated by the factory:

@injectable()
export class MyClass {

    public c: C; // This thing isn't injectable
    public d: D; // This thing isn't injectable

    // PHASE 1: instantiation
    constructor(
      @inject(A) a: A // This thing is
      @inject(B) b: B // This thing is
   ){
      ...
   }

   // PHASE 2: initialization
   public init(c: C, d: D) {
      this.c = c;
      this.d = d;
   }

}

The class that uses the factory:

@injectable()
export class SomeOtherClass {
   constructor(
      @inject("Factory<MyClass>") myClassFactory: (c: C, d: D) => MyClass
   ){
      // you only use "new" with entities that are not injected by inversify
      const c = new C(); 
      const d = new D();
      const myClass = myClassFactory(c, d);
   }
}

And the factory:

bind<interfaces.Factory<MyClass>>("Factory<MyClass>").toFactory(context =>
    (c: C, d, D) => {

        // PHASE 1: instantiation
        let myClass = context.kernel.get<MyClass>("MyClass"); // a and b are injected

        // PHASE 2: initialization
        myClass.init(c, d); // c and d are initialized

        return myClass;

    }
);

I hope it helps and please share your ideas on the GitHub issues if you think you know a better way.



来源:https://stackoverflow.com/questions/40767730/factory-with-parameters-in-inversifyjs

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!