IOC容器内的工厂 - Ninject
本文关键字:工厂 Ninject IOC | 更新日期: 2023-09-27 18:31:56
我正在阅读并了解.Net中的DependencyInjection。 我正在开发一个新项目并重构大量代码,在大多数情况下,它非常令人兴奋和有希望。 我现在正在尝试弄清楚如何使用工厂(在 Ninject 中 - 但此时任何 IOC 容器都可以工作)。
在下面的代码中,我正在用其他一些代码试水,并对这个概念感到满意。 但是,当我重构代码时,我有点坚持使用一种干净的方法来执行此操作。 如您所见,有很多重复。 另外,我不确定我是否应该将工厂塞进 IOC 容器中(并且不知道该怎么做),或者是否可以在 CompositionRoot 之外进行创建。 唯一真正重要的事情是 MeasurementType 枚举,因为其他代码依赖于此级别的区分类型。
有人可以指出我正确的方向吗? 我在网上看过,显然没有把它们放在一起。
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";
}
}
我会做这样的事情。
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)
}
}
它跳过了"测量类型"概念,但您可以通过Meters
实现IDistanceUnitOfMeasurement
并Knots
实现IVelocityUnitOfMeasurement
来管理它。
我会同意@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 方法替换它。当然,您还可以删除FluentAssertions。