代码之家  ›  专栏  ›  技术社区  ›  dukesta3

国际奥委会集装箱内的工厂-Ninject

  •  1
  • dukesta3  · 技术社区  · 13 年前

    我正在阅读并思考.Net中的DependencyInjection。我正在做一个新项目,重构了很多代码,在大多数情况下,这是非常令人兴奋和有希望的。我现在正试图弄清楚如何使用工厂(在Ninject中,但目前任何国际奥委会的集装箱都可以使用)。

    在下面的代码中,我用其他一些代码进行了测试,并对这个概念感到满意。然而,当我重构代码时,我有点拘泥于一种干净的方法。正如你所看到的,有很多重复。此外,我不确定是否应该将工厂藏在IOC容器中(不知道如何做到这一点),或者在CompositionRoot之外进行创建是否可以。唯一需要保留的真正重要的东西是MeasurementTypes枚举,因为其他代码在这个级别上依赖于区分类型。

    有人能给我指正确的方向吗?我在网上看了看,显然没有把所有的东西都整理好。

    public enum MeasurementTypes
    {
        Position,
        Distance,
        Altitude,
        Velocity,
        Clock
    }
    
    public enum VelocityTypes
    {
        [Description("meters / second")]
        MetersPerSecond,
        [Description("knots")]
        Knots
    }
    
    public enum DistanceTypes
    {
        [Description("meters")]
        Meters,
        [Description("Nautical Miles")]
        NauticalMiles,
        [Description("Statute Miles")]
        StatuteMiles
    }
    
    public class UnitOfMeasurementFactory
    {
        public static UnitOfMeasurement CreateUnitOfMeasurement(Enum type, string name = "anonymous", double value = 0)
        {
            if (type is VelocityTypes)
            {
                return VelocityUnitOfMeasurementFactory.CreateVelocityUnitOfMeasurement((VelocityTypes)type, name, value);
            }
            else if (type is DistanceTypes)
            {
                return DistanceUnitOfMeasurementFactory.CreateDistanceUnitOfMeasurement((DistanceTypes) type, name,
                                                                                        value);
            }
    
            throw new NotImplementedException();
        }
    }
    
    public class VelocityUnitOfMeasurementFactory
    {
        public static UnitOfMeasurement CreateVelocityUnitOfMeasurement(VelocityTypes velocityType, string name, double value)
        {
            UnitOfMeasurement uom;
    
            switch (velocityType)
            {
                case VelocityTypes.Knots:
                    uom = new Knots(name, value);
                    break;
                case VelocityTypes.MetersPerSecond:
                    uom = new MetersPerSecond(name, value);
                    break;
                default:
                    uom = new MetersPerSecond(name, value);
                    break;
            }
    
            return uom;
        }
    }
    
    public class DistanceUnitOfMeasurementFactory
    {
        public static UnitOfMeasurement CreateDistanceUnitOfMeasurement(DistanceTypes distanceType, string name,
                                                                        double value)
        {
            UnitOfMeasurement uom;
    
            switch (distanceType)
            {
                case DistanceTypes.Meters:
                    uom = new Meters(name, value);
                    break;
                case DistanceTypes.NauticalMiles:
                    uom = new NauticalMiles(name, value);
                    break;
                case DistanceTypes.StatuteMiles:
                    uom = new StatuteMiles(name, value);
                    break;
                default:
                    uom = new Meters(name, value);
                    break;
            }
    
            return uom;
            }
    }
    public sealed class Knots : UnitOfMeasurement
    {
        public Knots(string name, double value)
        {
            MeasurementType = MeasurementTypes.Velocity;
            RoundingDigits = 5;
            ConvertToBaselineFactor = .514444;
            ConvertFromBaselineFactor = 1.94384;
            Name = name;
            Value = value;
            Units = "knots";
    
        }
    }
    
    public sealed class Meters : UnitOfMeasurement
    {
        public Meters(string name, double value)
        {
            MeasurementType = MeasurementTypes.Distance;
            RoundingDigits = 5;
            ConvertToBaselineFactor = 1.0;
            ConvertFromBaselineFactor = 1.0;
            Name = name;
            Value = value;
            Units = "m";
        }
    }
    
    2 回复  |  直到 13 年前
        1
  •  2
  •   shamp00    13 年前

    我会做这样的事。

    interface IUnitOfMeasurementFactory
    {
        T Create<T>(string name, double value) where T: UnitOfMeasurement;
    }
    
    class Program
    {
        static void Main(string[] args)
        {
            var kernel = new StandardKernel();
            kernel.Bind<IUnitOfMeasurementFactory>().ToFactory();
    
            var factory = kernel.Get<IUnitOfMeasurementFactory>();
            var meters = factory.Create<Meters>("myDistance", 123.12);
            var knots = factory.Create<Knots>("mySpeed", 345.21)
        }
    }
    

    它跳过了“MeasurementTypes”概念,但您可以通过制作 Meters 使生效 IDistanceUnitOfMeasurement 和 Knots 使生效 IVelocityUnitOfMeasurement .

        2
  •  1
  •   BatteryBackupUnit    13 年前

    我会选择@shamp00的答案,但这里有一个有效的实现,就像你做事的方式一样:

    using System.ComponentModel;
    using System.Globalization;
    using System.Linq;
    using FluentAssertions;
    using Ninject;
    using Ninject.Activation;
    using Ninject.Parameters;
    using Ninject.Syntax;
    using Xunit;
    
    public class NinjectFactoryTest
    {
        [Fact]
        public void Test()
        {
            var kernel = new StandardKernel();
            kernel.Bind<IUnitOfMeasurementFactory>().To<UnitOfMeasurementFactory>();
            kernel.Bind<UnitOfMeasurement>().To<Knots>()
                .WhenClassifiedBy(VelocityUnitOfMeasurementFactory.BuildClassification(VelocityTypes.Knots));
    
            kernel.Bind<UnitOfMeasurement>().To<Meters>()
                .WhenClassifiedBy(DistanceUnitOfMeasurementFactory.BuildClassification(DistanceTypes.Meters));
    
            const string ExpectedName = "hello";
            const double ExpectedValue = 5.5;
    
            var actualUnitOfMeasurement = kernel.Get<VelocityUnitOfMeasurementFactory>()
                .CreateVelocityUnitOfMeasurement(VelocityTypes.Knots, ExpectedName, ExpectedValue);
    
            actualUnitOfMeasurement.Should().BeOfType<Knots>();
            actualUnitOfMeasurement.Name.Should().Be(ExpectedName);
            actualUnitOfMeasurement.Value.Should().Be(ExpectedValue);
        }
    }
    
    public class ClassifiedParameter : Parameter
    {
        public ClassifiedParameter(string classification)
            : base("Classification", ctx => null, false)
        {
            this.Classification = classification;
        }
    
        public string Classification { get; set; }
    }
    
    public static class ClassifiedBindingExtensions
    {
        public static IBindingInNamedWithOrOnSyntax<T> WhenClassifiedBy<T>(this IBindingWhenSyntax<T> syntax, string classification)
        {
            return syntax.When(request => request.IsValidForClassification(classification));
        }
    
        public static bool IsValidForClassification(this IRequest request, string classification)
        {
            ClassifiedParameter parameter = request
                .Parameters
                .OfType<ClassifiedParameter>()
                .SingleOrDefault();
    
            return parameter != null && classification == parameter.Classification;
        }
    }
    
    public enum MeasurementTypes
    {
        Position,
        Distance,
        Altitude,
        Velocity,
        Clock
    }
    
    public enum VelocityTypes
    {
        [Description("meters / second")]
        MetersPerSecond,
    
        [Description("knots")]
        Knots
    }
    
    public enum DistanceTypes
    {
        Meters,
        NauticalMiles,
        StatuteMiles
    }
    
    public interface IUnitOfMeasurementFactory
    {
        UnitOfMeasurement Create(string classification, string name, double value);
    }
    
    internal class UnitOfMeasurementFactory : IUnitOfMeasurementFactory
    {
        public const string ClassificationTemplate = "{0}://{1}";
    
        private readonly IResolutionRoot resolutionRoot;
    
        public UnitOfMeasurementFactory(IResolutionRoot resolutionRoot)
        {
            this.resolutionRoot = resolutionRoot;
        }
    
        public UnitOfMeasurement Create(string classification, string name, double value)
        {
            return this.resolutionRoot.Get<UnitOfMeasurement>(
                new ClassifiedParameter(classification),
                new ConstructorArgument("name", name),
                new ConstructorArgument("value", value));
        }
    }
    
    public class DistanceUnitOfMeasurementFactory
    {
        private readonly IUnitOfMeasurementFactory factory;
    
        public DistanceUnitOfMeasurementFactory(IUnitOfMeasurementFactory factory)
        {
            this.factory = factory;
        }
    
        public static string BuildClassification(DistanceTypes distanceType)
        {
            return string.Format(
                CultureInfo.InvariantCulture,
                UnitOfMeasurementFactory.ClassificationTemplate,
                MeasurementTypes.Distance.ToString(),
                distanceType.ToString());
        }
    
        public UnitOfMeasurement CreateDistanceUnitOfMeasurement(DistanceTypes distanceType, string name, double value)
        {
            string classification = BuildClassification(distanceType);
            return this.factory.Create(classification, name, value);
        }
    }
    
    public class VelocityUnitOfMeasurementFactory
    {
        private readonly IUnitOfMeasurementFactory factory;
    
        public VelocityUnitOfMeasurementFactory(IUnitOfMeasurementFactory factory)
        {
            this.factory = factory;
        }
    
        public static string BuildClassification(VelocityTypes velocityType)
        {
            return string.Format(
                CultureInfo.InvariantCulture,
                UnitOfMeasurementFactory.ClassificationTemplate,
                MeasurementTypes.Velocity.ToString(),
                velocityType.ToString());
        }
    
        public UnitOfMeasurement CreateVelocityUnitOfMeasurement(VelocityTypes velocityType, string name, double value)
        {
            string classification = BuildClassification(velocityType);
            return this.factory.Create(classification, name, value);
        }
    }
    
    public abstract class UnitOfMeasurement
    {
        public MeasurementTypes MeasurementType { get; set; }
    
        public int RoundingDigits { get; set; }
    
        public string Name { get; set; }
    
        public double Value { get; set; }
    
        public string Units { get; set; }
    }
    
    public sealed class Knots : UnitOfMeasurement
    {
        public Knots(string name, double value)
        {
            MeasurementType = MeasurementTypes.Velocity;
            RoundingDigits = 5;
            Name = name;
            Value = value;
            Units = "knots";
        }
    }
    
    public sealed class Meters : UnitOfMeasurement
    {
        public Meters(string name, double value)
        {
            MeasurementType = MeasurementTypes.Distance;
            RoundingDigits = 5;
            Name = name;
            Value = value;
            Units = "m";
        }
    }
    

    提示:它使用xunit([Fact]属性),但您可以很容易地用Main方法替换它。当然,你也可以删除FluentAssessments。

    推荐文章