通过依赖注入和配置/启动计时器传递计时器

时间:2013-07-18 16:07:07

标签: c# oop architecture dependency-injection software-design

我有一个情况,我需要一个在我班级中调用基于时间间隔的方法的计时器。

在正常情况下,我会实例化计时器并在构造函数本身中配置它。但我想在依赖注入风格中做到这一点。在构造函数中传递计时器很简单,但是为了将方法绑定到其OnTimeElapsed是棘手的,如果工厂实例化该类,配置此计时器?如何在不违反依赖注入原则的情况下继续前进。

由于

EDIT1

好的,让我重新说一下我真正想问的问题。

  1. 根据发布的视频 Misko
  2. 在他的其他演讲中(从不测试你的框架:.net框架 这里)
  3. in his code review guide什么都有 在构造函数中的字段赋值之外完成的操作被认为是错误的。
  4. 我实现依赖注入的主要目标是我需要在特定的时间内对是否调用方法进行单元测试。

    所以我的问题是:我应该在哪里绑定OnTimerElapsed事件? 我真的想在这里测试计时器吗? 我好像迷路了

    请帮助。

2 个答案:

答案 0 :(得分:3)

如果您的问题是,您希望依赖注入一个可以在以后绑定事件的计时器,那么它应该很简单。

只需创建Timer类即可关注ITimer界面并在其上创建方法以执行所需的操作。

public class Calendar
{
    public Calendar(ITimer timer)
    {
        // timer is the dependency injected timer
        timer.SetEvent(EventReminder, 3600);
    }

    public void EventReminder()
    {
        Console.Write("Hey, it's time for your appointment!");
    }

}

public interface ITimer
{
    void SetEvent(Action callbackMethod, int interval);
}

在这种情况下,您有一个日历应用程序,并且您希望应用程序具有计时器。但你不关心计时器是如何工作的,甚至不关心什么样的计时器(也许你想要一个可以在几分钟或几小时内工作的计时器,或者它可以以其他方式工作)。所有你知道的是你想要一个计时器,所以你依赖注入一个。

您必须创建一个界面,定义计时器将执行的操作,因为虽然它不关心您使用的计时器,但它确实关心计时器的功能。在我们的例子中,计时器可以做一件事 - 将事件设置为在一定间隔之后发生。

所以我们注入了计时器,但是为了能够使用或设置它,我们使用接口来定义方法。我们永远不知道它是如何在内部工作的 - 我们甚至不知道它有一个OnElapsedEvent,我们也不在乎。把它留给计时器的创建者,我们只想要一个能完成任务的方法,这就是上面代码演示的内容。

答案 1 :(得分:-2)

为新移民注册依赖注射。

我之前的有问题的代码在这里:

public class MyClassInvoker:IDisposable
{
    readonly Timer _myTimer;
    readonly MyClass _myclass;
    public MyClassInvoker(Timer myTimer, MyClass myclass)
    {
        _myTimer = myTimer;
        _myclass = myclass;
        _myTimer.Interval = 3000;//configure Your timer here
        _myTimer.Elapsed +=new ElapsedEventHandler(PeriodicInvoker); 
    }

    public void Start()
    {
        _myTimer.Start();
    }

    public void Dispose()
    {
        _myTimer.Dispose();
    }

    void PeriodicInvoker(object sender, EventArgs e)
    {
        _myclass.DoSomePeriodicWork();
    }
}

修改之后的代码:

public class MyClassInvoker:IDisposable
{
    readonly Timer _myTimer;
    readonly MyClass _myclass;
    public MyClassInvoker(MyClass myclass)
    {
        _myTimer = new Timer();
        _myclass = myclass;

    }

    public void Start()
    {
        _myTimer.Interval = 3000;//configure Your timer here
        //add or remove any previous listeners 
        //here depending upon the business needs

        _myTimer.Elapsed += new ElapsedEventHandler(PeriodicInvoker); 
        _myTimer.Start();
    }

    public void Dispose()
    {
        _myTimer.Dispose();
    }

    void PeriodicInvoker(object sender, EventArgs e)
    {
        _myclass.DoSomePeriodicWork();
    }
}

在直观地思考问题之后,我发布分析:

  1. 根据我自己的问题中发布的链接,永远不要做更多的工作 构造函数除了简单的赋值。我实际上是绑定了一个 构造函数中的事件处理程序。 我现在无法发表评论 如果我这样做,可能会产生影响。
  2. 我在之前的代码中传递了一个Timer对象,以便进行推广 可测试性。
  3. 有解释的解决方案

    1. 通过传递Timer作为依赖,我试图给出一个 模拟.Net计时器BCL的接口,以便单元测试以及替换。目前在.Net

      中有三种类型的计时器
      • System.Threading.Timer
      • System.Timers.Timer
      • System.Windows.Forms.Timer

      这些定时器都没有共享相同的接口,所以 将它们作为依赖项传递是没有意义的,我已经纠正过了 在我修改后的代码中。

    2. 如果按逻辑思考,将在之后调用Start方法 实例化MyClassInvoker类,所以如果我把事件绑定 那会很有意义。