InversifyJS Injecting Literal Constructor Parameters

前端 未结 1 1656
梦如初夏
梦如初夏 2021-02-06 14:35

Is it possible to get the below behaviour with InversifyJS:

constructor(IDependency resolvedDependency, string myLiteral)
                        ^                       


        
相关标签:
1条回答
  • 2021-02-06 14:53

    There are a few things that you can do. Here I will post a few of them...

    Injecting the literal as a constant value

    let TYPES = {
        IWarrior: Symbol("IWarrior"),
        IWeapon: Symbol("IWeapon"),
        rank: Symbol("rank")
    }
    
    interface IWeapon {}
    
    @injectable()
    class Katana implements IWeapon {}
    
    interface IWarrior {
        weapon: IWeapon;
        rank: string;
    }
    
    @injectable()
    class Warrior implements IWarrior {
        public weapon: IWeapon;
        public rank: string;
        public constructor(
            @inject(TYPES.IWeapon) weapon: IWeapon,
            @inject(TYPES.rank) rank: string
        ) {
            this.weapon = weapon;
            this.rank = rank;
        }
    }
    
    let kernel = new Kernel();
    kernel.bind<IWarrior>(TYPES.IWarrior).to(Warrior);
    kernel.bind<IWeapon>(TYPES.IWeapon).to(Katana);
    kernel.bind<string>(TYPES.rank).toConstantValue("master");
    

    Injecting the literal based on the context

    Using contextual constraints you could inject a constant value for a particular context:

    let kernel = new Kernel();
    kernel.bind<IWarrior>(TYPES.IWarrior).to(Warrior);
    kernel.bind<IWeapon>(TYPES.IWeapon).to(Katana);
    
    kernel.bind<string>(TYPES.rank)
        .toConstantValue("master")
        .whenTargetTagged("rank", "master");
    
    kernel.bind<string>(TYPES.rank)
          .toConstantValue("student")
          .whenTargetTagged("rank", "student");
    
    let master = kernel.getTagged(TYPES.IWarrior, "rank", "master");
    let student = kernel.getTagged(TYPES.IWarrior, "rank", "student");
    

    injecting a factory

    let TYPES = {
        IWarrior: Symbol("IWarrior"),
        IWeapon: Symbol("IWeapon"),
        IFactoryOfIWarrior: Symbol("IFactory<IWarrior>")
    }
    
    interface IWeapon {}
    
    @injectable()
    class Katana implements IWeapon {}
    
    interface IWarrior {
        weapon: IWeapon;
        rank: string;
    }
    
    @injectable()
    class Warrior implements IWarrior {
        public weapon: IWeapon;
        public rank: string;
        public constructor(
            @inject(TYPES.IWeapon) weapon: IWeapon
        ) {
            this.weapon = weapon;
            this.rank = null; // important!
        }
    }
    
    let kernel = new Kernel();
    kernel.bind<IWarrior>(TYPES.IWarrior).to(Warrior);
    kernel.bind<IWeapon>(TYPES.IWeapon).to(Katana);
    
    kernel.bind<inversify.IFactory<IWarrior>>(TYPES.IFactoryOfIWarrior)
        .toFactory<IWarrior>((context) => {
            return (rank: string) => {
                let warrior = context.kernel.get<IWarrior>(TYPES.IWarrior);
                warrior.rank = rank;
                return warrior;
            };
        });
    
    let warriorFactory = kernel.get<inversify.IFactory<IWarrior>>(TYPES.IFactoryOfIWarrior);
    
    let master = warriorFactory("master");
    let student = warriorFactory("student");
    

    You can inject factories into other classes:

    @injectable()
    class Army {
        private _warriorFactory: (rank: string) => IWarrior;
        private _soldiers: IWarrior[];
        public constructor(
            @inject(TYPES.IFactoryOfIWarrior) warriorFactory: (rank: string) => IWarrior
        ) {
            this._warriorFactory = warriorFactory;
            this._soldiers = [];
        }
        public newRecruit(rank: string) {
            this._soldiers.push(this._warriorFactory(rank));
        }
    }
    

    I think that the best solution is to use a factory.

    0 讨论(0)
提交回复
热议问题