在此示例中,如何使用SystemClock解决IClock?

时间:2014-03-28 12:55:37

标签: c#-4.0 dependency-injection inversion-of-control factory

我正试图从这个截屏视频中学习IOC原理 Inversion of Control from First Principles - Top Gear Style

我尝试按照截屏播放但我在 AutomaticFactory 尝试创建 AutoCue 的对象时出错。 AutoCue类有contructor,它接受IClock而不是 SystemClock 。但我的问题是,在截屏 IClock 中使用 SystemClock 解决了内部 AutomaticFactory 。但在我的代码中, IClock 没有得到解决。我错过了什么吗?

class Program
{
    static void Main(string[] args)
    {
        //var clarkson = new Clarkson(new AutoCue(new SystemClock()), new Megaphone());
        //var clarkson = ClarksonFactory.SpawnOne();
        var clarkson = (Clarkson)AutomaticFactory.GetOne(typeof(Clarkson));
        clarkson.SaySomething();
        Console.Read();
    }
}
public class AutomaticFactory
{
    public static object GetOne(Type type)
    {
        var constructor = type.GetConstructors().Single();
        var parameters = constructor.GetParameters();

        if (!parameters.Any()) return Activator.CreateInstance(type);

        var args = new List<object>();

        foreach(var parameter  in parameters)
        {
            var arg = GetOne(parameter.ParameterType);
            args.Add(arg);
        }

        var result = Activator.CreateInstance(type, args.ToArray());

        return result;
    }
}

public class Clarkson 
{
    private readonly AutoCue _autocue;
    private readonly Megaphone _megaphone;
    public Clarkson(AutoCue autocue,Megaphone megaphone)
    {
        _autocue = autocue;
        _megaphone =megaphone;
    }
    public void SaySomething()
    {
        var message = _autocue.GetCue();
        _megaphone.Shout(message);
    }
}

public class Megaphone
{
    public void Shout(string message)
    {
        Console.WriteLine(message);
    }
}
public interface IClock
{
    DateTime Now { get; }
}

public class SystemClock : IClock
{
    public DateTime Now { get { return DateTime.Now; } }
}

public class AutoCue
{
    private readonly IClock _clock;

    public AutoCue(IClock clock)
    {
        _clock = clock;
    }
    public string GetCue()
    {
        DateTime now = _clock.Now;
        if (now.DayOfWeek == DayOfWeek.Sunday)
        {
            return "Its a sunday!";
        }
        else
        {
            return "I have to work!";
        }  
    }
}

1 个答案:

答案 0 :(得分:4)

您基本上实现的是一个小型IoC容器,它能够自动连接对象图。但是您的实现只能创建具体对象的对象图。这会使您的代码违反Dependency Inversion Principle

实现中缺少的是某种Register方法告诉你的AutomaticFactory,当面对抽象时,它应该解决注册的实现。这看起来如下:

private static readonly Dictionary<Type, Type> registrations = 
    new Dictionary<Type, Type>();

public static void Register<TService, TImplementation>() 
    where TImplementation : class, TService
    where TService : class
{
    registrations.Add(typeof(TService), typeof(TImplementation));
}

不,您也必须对GetOne方法进行调整。您可以在GetOne方法的开头添加以下代码:

    if (registrations.ContainsKey(type))
    {
        type = registrations[type];
    }

这将确保如果提供的typeAutomaticFactory中注册为TService,则将使用映射的TImplementation,并且工厂将继续使用此实现要建立的类型。

但这确实意味着您现在必须明确注册IClockSystemClock之间的映射(如果您正在使用IoC容器,这是很自然的事情)。您必须在从AutomaticFactory解析第一个实例之前进行此映射。因此,您应该将以下行添加到Main方法的开头:

AutomaticFactory.Register<IClock, SystemClock>();