我正在阅读并绕过.Net中的DependencyInjection。我正在开发一个新项目并重构很多代码,而且大多数情况下它非常令人兴奋和充满希望。我现在正在尝试研究如何使用工厂(在Ninject中 - 但任何IOC容器都可以在这一点上工作)。
在下面的代码中,我正在使用其他一些代码测试水域,并对这个概念感到满意。但是,当我重构代码时,我有点坚持干净的方式来做到这一点。如你所见,有很多重复。另外,我不确定是否应该将工厂放在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";
}
}
答案 0 :(得分:2)
我会做这样的事情。
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
来管理它。
答案 1 :(得分:1)
我会选择@ 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,当然,你可以删除。