当其中一个实现需要额外的步骤时,C#模式用于避免泄漏抽象

时间:2016-03-09 13:24:30

标签: c# .net design-patterns leaky-abstraction

我正在实现一个类似于{/ p>的ITracker界面

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

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

我不想仅仅因为其中一个实现需要使用ITracker方法来污染Flush()接口。它会感觉像是一个漏洞的抽象。

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

当会话结束时对Tracker进行垃圾回收时,是否可以调用方法?这甚至是一个好方法吗?

我觉得我在这里错过了一招!

4 个答案:

答案 0 :(得分:5)

我要使ITracker使用与事务相似的模式,因为可能存在您可能想要丢弃跟踪器事件,回滚或修改它们的情况:

public interface ITracker
{
    void Track(ITrackerEvent trackerEvent);

    void Commit();
}

然后按实施方式:

  • 我在Flush内拨打Commit了解应用洞察。
  • 我在List<ITrackerEvent>方法内写入内存中集合中的跟踪器事件(BlockingCollection<ITrackerEvent>Track,如果涉及并发),然后使用当前逻辑调用{{1在Mixpanel.NET的{​​{1}}方法实现中的api。

建议: Commit也应该实施Mixpanel.NET,因为跟踪器通常会使用需要处理的资源。

答案 1 :(得分: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()方法包含在跟踪中发生错误时调用的委托。

答案 2 :(得分:3)

我只是从ITracker派生IDisposable。实现此接口的类可以选择在Dispose方法中执行某些操作,例如你的Flush,或什么都不做。

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

此外,请查看Observable patternITracker名称表示您可能希望在更改对象状态时执行某些操作。

答案 3 :(得分:1)

听起来你正在缓冲某些东西 - 被跟踪的东西需要不时刷新。你的界面隐藏了这种行为,这很好 - 当你的界面被刷新或者它被缓冲时,你不应该从该界面告诉你。

如果它是高容量我想设置两个参数 - 最大刷新间隔和最大缓冲区大小。 第一个使用计时器定期刷新。第二个在达到容量时触发刷新。然后,当物品被丢弃或收集时,我再次冲洗。

我将缓冲区分离到自己的类中,因此我可以重复使用它并单独对其进行单元测试。我会看是否能找到它,但写的代码不多。