3

我在这里有一种情况,我需要在我的类中使用一个计时器,它根据时间间隔调用一些方法。

在正常情况下,我会实例化计时器并在构造函数本身中对其进行配置。但我想以依赖注入的方式来做。在构造函数中传递计时器很容易,但是为了将一个方法绑定到它的 OnTimeElapsed 是很棘手的,工厂实例化该类是否应该配置这个计时器?在不违反依赖注入原则的情况下,我应该如何继续。

谢谢

编辑1

好的,让我重新表述我真正想问的问题。

  1. 根据 米斯科发布的视频
  2. 在他的其他谈话中(从不测试你的框架:.net framework here)
  3. 在他的代码审查指南中,除了构造函数中的字段分配之外所做的任何事情都被认为是不好的。

我实现依赖注入的主要目标是,我需要在特定的经过时间对某个方法是否被调用进行单元测试。

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

请帮助。

4

2 回答 2

6

如果您的问题是,您想依赖注入一个计时器,以后可以将事件绑定到该计时器,它应该很简单。

只需创建您的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,我们也不在乎。把它留给计时器的创建者,我们只需要一种方法来完成任务,这就是上面的代码所展示的。

于 2013-07-18T16:12:46.727 回答
-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 对象,以提高可测试性。

有解释的解决方案

  1. 通过将 Timer 作为依赖项传递,我试图提供一个模拟 .Net Timer BCL 的接口,以便进行单元测试并进行替换。目前.Net中有三种类型的定时器

    • System.Threading.Timer
    • System.Timers.Timer
    • System.Windows.Forms.Timer

    这些计时器都不共享相同的接口,因此将它们作为依赖项传递是毫无意义的,我已在修改后的代码中更正了这一点。

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

于 2013-09-01T02:32:51.410 回答