界面应该有多严格(一个好的界面设计)

时间:2014-04-04 10:23:36

标签: c# interface dependency-injection

我不确定这是否适用于StackOverflow,或者更确切地说可能适用于Programmers @ StackExchange。如果这应该去那里,请在下面的评论中告诉我,我会移动它:)

无论如何 - 回到原点。我从未使用接口和Constructor / Property依赖注入等进行过多编程。所以我对它了解得太多了。我一直在阅读一些文章,主要是this,并发现这是一种有趣的技术,可以使我的软件更加灵活和可测试。
所以关闭我开始重构一个现有的应用程序(C#),我遇到了两难选择,下面两个选项之一更好:
选择1 - 函数中的最低依赖性要求。为构造函数留下一些注入(使用接口时的实现决策)

public interface IDriver
{
    bool Start();
    bool Stop();
    bool Read(uint[] signal1, uint[] signal2);
}

public class MyDriver : IDriver
{
    public MyDriver(ISettings settings)
    {
        //remember ISettings in a local var
    }

    //interface implementation
}

选择2 - 函数调用中所有必需的依赖项。

public interface IDriver
{
    bool Start();
    bool Stop();
    bool Read(ISettings settings, uint[] signal1, uint[] signal2);
}

public class MyDriver : IDriver
{
    //implementation of the interface
}

现在选择2可能是错的,对吧?因为某些实现可能实际上不需要ISettings工作。我目前实施IDriver使用ISettings的事实并不意味着它将在一年左右的时间内完成,因此合乎逻辑的方法是使用方法1.

所以我的问题是:我应该如何严格制作界面,以及如何在界面和实现之间混淆?我不希望实现影响我设计界面的方式 另外,有没有人知道有关该主题的好文章?

感谢。

3 个答案:

答案 0 :(得分:2)

接口应该由使用接口的客户端定义和拥有。正如Agile Principles, Patterns, and Practices解释的那样,“clients [...]拥有抽象接口”(第11章)。因此,如果客户端需要这个(您的选项1):

public interface IDriver
{
    bool Start();
    bool Stop();
    bool Read(uint[] signal1, uint[] signal2);
}

然后那应该是界面。其他所有内容都是实现细节,应该放在构造函数中。

答案 1 :(得分:0)

不仅仅是严格,还是合同必要性的问题。

您的阅读功能是否合同需要ISettings?可能没有。

认为它与signal1和signal2变量没有区别。你在接口的Read方法定义中有signal1和signal2的原因是因为它们是合同的一部分,并且对于用作输入的接口的每个实现都是必需的。

但ISettings听起来像某个特定实现需要的东西,而其他一些则不会。 (如Loggers,CacheManagers,Repositories等)

所以你是对的,而且往往更好,方法#1会更好。它保持界面清洁和仅限于确切的合同输入/输出。

答案 2 :(得分:0)

彻底研究系统需求可以解决许多问题,并帮助您更自信地设计应用程序。所以首先要多思考,直到你达到一个可以争论和推理你将要做的事情为止的点。

其次恕我直言,两种方法都可以。第一个作为' raja'指出是干净和有吸引力的,我不会再重复他说的话。但请考虑这种情况:如果稍后需要配置IDriver实现者​​。然后通过某种设置解决了许多问题。即使在目前这一刻你认为它是不必要的(我承认这是YAGNI原则所说的),你可以提供空设置(NullObject pattern):

public Driver : IDriver
{
   public bool Read(ISettings settings, uint[] signal1, uint[] signal2)
   {
      if (settings.PreventSomeThing)
      {
         .....
      }

   }
}

public NullSetting : ISetting
{
   public bool PreventSomething = false;   
   ....
}