IoC (Ninject) and Factories

前端 未结 4 1715
长发绾君心
长发绾君心 2020-12-09 03:15

If I have the following code:

public class RobotNavigationService : IRobotNavigationService {
  public RobotNavigationService(IRobotFactory robotFactory) {
          


        
4条回答
  •  轻奢々
    轻奢々 (楼主)
    2020-12-09 03:50

    I was looking for a way to clean up a massive switch statement that returned a C# class to do some work (code smell here).

    I didn't want to explicitly map each interface to its concrete implementation in the ninject module (essentially a mimic of lengthy switch case, but in a diff file) so I setup the module to bind all the interfaces automatically:

    public class FactoryModule: NinjectModule
    {
        public override void Load()
        {
            Kernel.Bind(x => x.FromThisAssembly()
                                .IncludingNonPublicTypes()
                                .SelectAllClasses()
                                .InNamespaceOf()
                                .BindAllInterfaces()
                                .Configure(b => b.InSingletonScope()));
        }
    }
    

    Then create the factory class, implementing the StandardKernal which will Get the specified interfaces and their implementations via a singleton instance using an IKernal:

        public class CarFactoryKernel : StandardKernel, ICarFactoryKernel{
        public static readonly ICarFactoryKernel _instance = new CarFactoryKernel();
    
        public static ICarFactoryKernel Instance { get => _instance; }
    
        private CarFactoryKernel()
        {
            var carFactoryModeule = new List { new FactoryModule() };
    
            Load(carFactoryModeule);
        }
    
        public ICar GetCarFromFactory(string name)
        {
            var cars = this.GetAll();
            foreach (var car in cars)
            {
                if (car.CarModel == name)
                {
                    return car;
                }
            }
    
            return null;
        }
    }
    
    public interface ICarFactoryKernel : IKernel
    {
        ICar GetCarFromFactory(string name);
    }
    

    Then your StandardKernel implementation can get at any interface by the identifier of you choice on the interface decorating your class.

    e.g.:

        public interface ICar
    {
        string CarModel { get; }
        string Drive { get; }
        string Reverse { get; }
    }
    
    public class Lamborghini : ICar
    {
        private string _carmodel;
        public string CarModel { get => _carmodel; }
        public string Drive => "Drive the Lamborghini forward!";
        public string Reverse => "Drive the Lamborghini backward!";
    
        public Lamborghini()
        {
            _carmodel = "Lamborghini";
        }
    }
    

    Usage:

            [Test]
        public void TestDependencyInjection()
        {
            var ferrari = CarFactoryKernel.Instance.GetCarFromFactory("Ferrari");
            Assert.That(ferrari, Is.Not.Null);
            Assert.That(ferrari, Is.Not.Null.And.InstanceOf(typeof(Ferrari)));
    
            Assert.AreEqual("Drive the Ferrari forward!", ferrari.Drive);
            Assert.AreEqual("Drive the Ferrari backward!", ferrari.Reverse);
    
            var lambo = CarFactoryKernel.Instance.GetCarFromFactory("Lamborghini");
            Assert.That(lambo, Is.Not.Null);
            Assert.That(lambo, Is.Not.Null.And.InstanceOf(typeof(Lamborghini)));
    
            Assert.AreEqual("Drive the Lamborghini forward!", lambo.Drive);
            Assert.AreEqual("Drive the Lamborghini backward!", lambo.Reverse);
        }
    

提交回复
热议问题