【问题标题】:Make a class dependency appear in interface without it being a property使类依赖项出现在界面中而不是属性
【发布时间】:2012-03-11 17:43:32
【问题描述】:

我有一个接口和一个实现该接口的类。

我要求该类依赖于 ITimer。创建一个私有成员并传入一个构造函数参数,并将私有成员分配给该构造函数参数。

如何使接口以某种方式声明此 ITimer 但不作为属性?好像我不能正确测试 MyClass ,但我认为接口应该是类必须遵守的合同,因此我的类具有依赖关系,那么如何让它出现在接口中?

public interface IMyInterface
{
  void DoSomething();
}

public class MyClass : IMyInterface
{
  private ITimer MyTimer;

  public MyClass(ITimer timer)
  {
    MyTimer = timer;
  }

  public void DoSomething()
  {

  }
}

【问题讨论】:

  • 听起来您希望能够让接口强制所有实现类都有一个接受ITimer 的构造函数,对吗? (顺便说一句,您将无法使用界面执行此操作)
  • 技术上不是所提出问题的答案,而是解决您的问题。如何定义 MyClassBase(抽象基类/类型)并针对它进行编码(相对于接口)?

标签: c# .net oop interface


【解决方案1】:

这不能通过 C# 中的接口来完成。你可以做的是从接口的抽象类继承。

public abstract class AMyClass
{
  protected ITimer MyTimer;

  public AMyClass(ITimer timer)
  {
    MyTimer = timer;
  }

  public abstract void DoSomething();
}

public class MyClass : AMyClass
{
  public override void DoSomething()
  {

  }
}

【讨论】:

  • 是的——这是提问者正在寻找的正确答案。接口不能定义对象是如何构造的,因为它——根据定义——没有定义实现。但是,要记住的一件事是,有一个看起来不像接口的实现是可以的,因为接口只是为消费者服务的。因此,要么使用一个基本抽象类——它甚至可以从接口继承——要么保持不同的实现。如果您有任何问题,请告诉我们。
【解决方案2】:

这行不通,但它行不通是件好事:

您对ITimer 的依赖不是界面 的一部分,它是界面的实现 的一部分 - 所以从界面中隐藏它是正确的东西。

如果接口的所有实现都需要对ITimer 的依赖(并且如果需要),则应附加您的接口声明以解决此问题。

【讨论】:

  • 如果不将依赖项设为属性,您将如何做到这一点?
  • 这当然取决于您的代码所做的事情,但我可能会使用无参数构造函数和作为接口一部分的 setTimer() 方法。
  • 我认为构造函数中的 ITimer 仍然是合适的,但在接口中有一个名为 SetTimer() 的方法是一个好主意,因为它表明需要一个计时器。它显然不会将 ITimer 暴露为接口依赖项,但它可能更接近于确保所有类实现都使用计时器
  • 再一次,如果不了解代码的真正作用,我没有坚实的基础可以判断。
  • 例如,如果接口具有 UseTimer 属性,并且在 DoSomething 方法中,如果它为 true,则它会设置一个计时器
【解决方案3】:

为什么属性不合适?您可以拥有一个带有私有 setter 的属性,它似乎完全符合您的需要。

其他选项是从具有受保护 Timer 的抽象基类派生并同时实现接口。

理论上,依赖注入正是您所寻找的。所以看看 Inversion of Control 容器可能是值得的。

【讨论】:

  • 如果你在类中有一个私有的设置器,它不会实现接口,因为它必须是公共的。我猜抽象类是正确的答案
  • 你为什么不想像这样添加smth?接口 IMyInterface { int ITimer MyTimer { 获取; } } 内部类 MyClass IMyInterface { public ITimer MyTimer { get;放; } }
【解决方案4】:

如果您在接口上有一个明确不想要的依赖项,例如 ITimer,那么它听起来像是一个实现细节,所以它没有被定义为 正确合同的一部分。一种方法是“忘记ITimer;只有某些实现可能需要它,这是 IoC/DI 解析器所关心的问题”。

显然,构造函数不是接口的一部分。我能想到的唯一另一件事(同时将IMyInterface 保留在API 之外)是拥有一个IMyInterfaceFactory 接口,使用Create 方法,该方法采用ITimer - 但这会强制特别一组依赖,可能不反映实际的实现。

如果上述套件都不是,并且ITimer 基本上 是界面的一部分,我会正式 成为界面的一部分。

【讨论】:

  • 如果你让它成为界面的一部分,你就将它公开,你不希望允许用户更改 ITimer 的一部分。说您可能需要公开诸如 Interval 之类的属性,所以我想如果您使某些东西可见,那么我想公开整个计时器可能是可以的
  • @Jon ITimer 的内部结构我完全留给ITimer。你没有展示它是如何定义的,所以我不能赞扬它。
  • 目前它公开了 System.Timers.Timer 的所有属性
【解决方案5】:

接口是类公开的能力的契约。如果接口中没有ITimer 的自然位置,那么它看起来就像实现它的特定类中的实现细节,因此应该保留在类中。

【讨论】:

    【解决方案6】:

    如果一个类不使用ITimer就可以实现你的接口,那它不遵守接口吗?显然是的。

    ITimer 的使用是一个实现细节,因此不应在接口中表示。

    【讨论】:

      猜你喜欢
      • 2011-08-13
      • 1970-01-01
      • 2012-01-02
      • 1970-01-01
      • 1970-01-01
      • 2011-02-04
      • 1970-01-01
      • 2013-02-09
      • 1970-01-01
      相关资源
      最近更新 更多