5

我正在实现一个ITracker看起来像这样的接口:

public interface ITracker
{
    void Track(ITrackerEvent trackerEvent);
}

我最初创建了一个封装 Mixpanel.NET 的接口实现。然后,我创建了另一个包装 Application Insights 的产品。但是,Application Insights 需要Flush()将数据发送到服务器。

我不想仅仅因为其中一个实现需要一个方法而污染ITracker接口。Flush()感觉就像一个泄漏的抽象。

但是,我需要在某个时候调用此方法(可能在应用程序关闭时),并且不想每次Track调用时都这样做。

当 Tracker 在会话结束时被垃圾收集时,是否可以调用方法?这甚至是一个好方法吗?

我觉得我在这里错过了一个技巧!

4

4 回答 4

5

我会ITracker使用类似事务的模式,因为在某些情况下您可能想要丢弃跟踪器事件、回滚或修改它们:

public interface ITracker
{
    void Track(ITrackerEvent trackerEvent);

    void Commit();
}

然后每个实现:

  • 我会Flush在内部致电Commit以获取应用程序见解。
  • 我会在方法内部的内存集合(List<ITrackerEvent>或者BlockingCollection<ITrackerEvent>如果涉及并发)中编写跟踪器事件,Track然后使用您当前的逻辑在方法实现中调用Mixpanel.NETapi 。CommitMixpanel.NET

建议: ITracker也应该实施IDisposable,因为跟踪器通常使用需要处置的资源。

于 2016-03-09T13:32:04.750 回答
5

在 Leri 的基础上,我会更多地考虑跟踪器可能需要做的事情。

我倾向于做这样的事情:

public interface ITracker {
    void BeginTracking();
    void Track(ITrackerEvent trackerEvent);
    void EndTracking();
}

然后所有的跟踪器都知道他们什么时候开始,什么时候结束。这很重要,因为跟踪器可能持有不应持有超过必要时间的资源。如果跟踪器不需要使用BeginTrackingEndTracking,则实现是微不足道的。简单的实现不是泄漏的抽象。泄漏抽象是一种不适用于所有实现的抽象。

现在假设您完全反对在每个跟踪器中使用两种额外的方法(为什么?)。相反,您可以使用带外的 ITrackerEvents 并涵盖 Begin 和 End 的语义含义。我不喜欢这个。它要求每个跟踪器都有特殊的代码来处理带外事件。

你也可以有一个单独的界面

public interface IDemarcatedTracker : ITracker {
    void BeginTracking();
    void EndTracking();
}

这要求您在调用代码中有特殊情况代码以检查 ITracker 是否也是 IDemarcatedTracker:

public void BeginTracking(ITracker tracker)
{
    IDemarcatedTracker demarcatedTracker = tracker as IDemarcatedTracker;
    if (demarcatedTracker != null)
        demarcatedTracker.BeginTracking();
}

并且不要过度吹嘘事情,但我也想知道当跟踪器失败时应该发生什么?只是一味的抛出异常?这就是抽象实际上存在漏洞的地方。跟踪器没有任何流程可以让您知道它无法跟踪。

在您的情况下,您可能希望返回布尔值(有限信息)、错误代码(更多信息)或错误类/结构。或者您可能希望抛出一个标准异常。或者您可能希望 Begin() 方法包含一个委托,以便在跟踪中发生错误时调用。

于 2016-03-09T13:59:21.290 回答
3

我只是ITrackerIDisposable. 实现此接口的类可以选择在Dispose方法中执行某些操作,例如 your Flush,或者什么也不做。

public interface ITracker : IDisposable
{
    void Track(ITrackerEvent trackerEvent);
}

另外,请查看Observable 模式ITracker顾名思义,当对象的状态发生更改时,您可能希望执行一些操作。

于 2016-03-09T14:13:43.547 回答
1

听起来你正在缓冲一些东西——被跟踪的东西需要不时刷新。您的界面隐藏了该行为,这很好 - 您应该无法从该界面判断它何时被刷新或即使它正在缓冲。

如果它是大容量的,我喜欢设置两个参数 - 最大刷新间隔和最大缓冲区大小。第一个使用计时器定期刷新。当达到容量时,第二个触发刷新。然后在处理或收集对象时再次刷新。

我将缓冲区分离到它自己的类中,这样我就可以重用它并独立地对其进行单元测试。我看看能不能找到,不过代码不多。

于 2016-03-10T02:41:19.817 回答