无用的接口

时间:2009-06-05 14:02:10

标签: design-patterns interface

如果您只想实现一个接口,为什么要使用接口呢?

25 个答案:

答案 0 :(得分:28)

如果我知道只有一个实现,我就不会创建一个接口。这属于YAGNI,IMO。

(当然,我很少了解事实的未来......)

答案 1 :(得分:22)

将API与实现分开,这通常是一种很好的编程习惯。如果没有别的话,它将有助于提高可读性。它还允许将来使用您的代码的人提供接口的替代实现,如果他们愿意的话。

答案 2 :(得分:10)

最好将interface设置为规范,以便将class编码为。

如果您确定了interface将拥有的公共方法/功能,则可以将其锁定到位。然后,当您考虑到明确的功能时,对class进行编码会变得更加容易。

我认为让编写好的代码比保持代码库清洁更容易。

答案 3 :(得分:8)

因为他们错过了C ++头文件?

答案 4 :(得分:4)

当人们为每个类创建一个Interface,一个Abstract和一个实际的实现时,它也会让我感到困扰,即使它永远不会有多个,并且这三个文件几乎都是空的。

然而,大用途是:

  1. 未来扩展/增强占位符

  2. 易于实现控制/依赖注入的反转

  3. 易于实施模拟单元测试。

  4. *编辑:

    我注意到你的标签中也有Spring。如果使用Spring,则上面的#2可能是最重要的。它更容易设计期望接口的类,并且您可以在Spring配置(依赖注入)中交换接口的实际实现。

答案 5 :(得分:4)

如果确实存在一个实现并且只是一个实现,则不要编写接口代码。 (YAGNI)。

然而,99%的时间至少有两个类的实现,一个是真实的,一个用于测试。

在测试过程中分离和模拟系统各部分的简易性非常值得为一个类创建一个接口。

作为旁注,也许这只是因为我缺乏一些自我控制,对接口的编码使我在处理特定类时更加专注。我发现自己更多地考虑“我调用的这个界面将返回/执行此操作”而不是“这个类我的工作方式是这样的,它调用x,转换y,与z通信,将咖啡放入,使枕头,相对于y整合n然后返回一个猴子的实例......等等,我又在做什么?“

答案 6 :(得分:3)

同意我一直看到这一点,它确实是我的坚果。如果暂时他们只是一个实现而且不太可能更多,那么我会在下一个开发人员认为合适时确定并实现该接口。

答案 7 :(得分:3)

如果你只有一个实现,我不会这样做。这里提出的论点,你可能有多个实现,并没有真正经得起仔细检查。如果最终实现多个实现,则使用内置的Visual Studio工具或Resharper提取界面大约需要5秒钟。

所以,是的,YAGNI - 在你不得不这样做之前不要让你的生活复杂化。

答案 8 :(得分:3)

某些技术要求您使用接口。一个 COM 。他们通常只有一个类实现你的界面。

答案 9 :(得分:2)

当您使用允许您将函数作为一阶值传递的语言时,通常可以避免单方法接口。举几个例子来说明:


传递实现逻辑片段的单方法接口:

public interface IComparable<T>
{
    int CompareTo(T first, T second);
}

public static class Array<T>
{
    public void Sort(T[] input)
    {
        if (T is IComparable) { /* sorting implementation */ }
        else { Throw new Exception("Doesn't implement IComparable"); }
    }
}

可替换为:

public static class Array<T>
{
    public void Sort(T[] input, Func<T, T, int> compare)
    {
        /* sorting implementation */
    }
}

我认为上面的功能风格更具可读性和可重用性。


依赖注入/模拟的单方法接口:

public interface IFailureNotifier
{
    void HandleFailure(Exception ex);
}

public class TransactionProcessor
{
    public IFailureNotifier FailureNotifier { get; set; }

    public TransactionProcessor(IFailureNotifier failureNotifier)
    {
        this.FailureNotifier = failureNotifier;
    }

    public void ProcessItems(object[] items)
    {
        try
        {
            for(object item in items) { /* do stuff */ }
        }
        catch(Exception ex)
        {
            FailureNotifier.HandleFailure(ex);
        }
    }
}

可以重写为:

public class TransactionProcessor
{
    public Action<Exception> FailureNotifier { get; set; }

    public TransactionProcessor(Action<Exception> failureNotifier)
    {
        this.FailureNotifier = failureNotifier;
    }

    public void ProcessItems(object[] items)
    {
        try
        {
            for(object item in items) { /* do stuff */ }
        }
        catch(Exception ex)
        {
            FailureNotifier(ex);
        }
    }
}

这种方法的优点是更简单的类库:我不需要使用微小的对象来实现IFailureNotifier的单一方法,我只是直接传递实现。


这并不是说单方法接口,如果函数依赖于潜在的可变状态,你仍然希望在接口中包装一个函数。但是我个人发现单方法接口的大部分好处已经由一流的函数提供。

答案 10 :(得分:2)

一个原因可能是解耦:如果您的类被其他开发人员使用,您可以为他提供接口的源代码,并为自己保留实现细节。

如果实现发生变化,并且接口中定义的“合同”没有,那么您会很高兴:您的界面仍然描述了该类的功能,并且没有人必须知道它是如何实现的。

答案 11 :(得分:1)

在某些情况下,为了可见性:您可能希望代码的某些部分能够看到具体的类并且可以访问setter,而其他一些部分只能看到getter:只允许它们访问接口。

使用public / protected / private无法始终实现这一目标。

答案 12 :(得分:1)

是的,特别是使用Delphi。

如果您有一个对象的接口引用,那么您将自动获得引用计数。因此,当您希望自动清理对象时,只有一个实现的界面是很常见的。引用计数优于垃圾收集,因为只要最后一个引用超出范围或不再引用它,就会调用对象的析构函数。

答案 13 :(得分:1)

如果您正在使用允许重构的系统,则只应添加接口(如果规范需要它(例如,外部API)或者您需要多个实现)。我认为测试对象是有效的解释,所以如果你需要一个接口来测试它,那就很好地使用了接口。

值对象应该很少成为接口,服务对象应该经常成为接口。

答案 14 :(得分:1)

当我在项目中与其他人合作时,例如,如果我做前端(例如Web应用程序)而另一个人做所有数据库工作,我们首先编写API。面对我的一面是关于问题域:用户,管理员,员工,SKU等等的类。然后我们可以独立工作;她实现了所有接口,并编写了使用它们的代码。

答案 15 :(得分:0)

因为你将来最终会有两个或更多

<强> ADDITION 看完一些评论后: 对象模拟:这意味着你将拥有多个接口实现,yoru mock是另一个实现。

答案 16 :(得分:0)

其他一些答案提到“与他人合作”,这当然是一个问题。一个拥有10个程序员的项目将不得不采用不同于一个项目的方式进行处理,不幸的是,以多种人可以为其做出贡献的方式布置软件架构是人们似乎总是在努力学习的方式。 / p>

有人可以推荐任何好书或文章吗?

答案 17 :(得分:0)

我经常这样做,原因如下:

1)它允许您指定类的哪些特征实际在类外使用。这告诉您只要该接口保持不变,您始终需要支持哪些功能。这允许您出于任何原因在该类中拥有其他公共方法(以支持其他接口或具有该对象实例的其他对象,并通过实际类名称而不是通过接口引用它)。

2)它还将通过intellisense提供的列表减少到仅接口支持的功能。

3)如上所述,它对单元测试和模拟框架很有用。

答案 18 :(得分:0)

为了促进松耦合,依靠抽象依赖而不是将自己与具体类联系起来被认为是更好的设计。

这种做法特别有用的一个例子是Spring的proxy-based remoting方法,其中你的单个实现驻留在不同的JVM中。

答案 19 :(得分:0)

仅一个实现的接口的一种情况:RMI。您在一个应用程序上有一个对象,并将通过RMI从另一个应用程序中使用它;你需要有一个界面。这样你甚至不必在调用应用程序中包含实现类,这可能会使调用应用程序不包含一堆J2EE内容或实现可能使用的外部库。

另一个原因:今天你只有一个实现,但明天可能会有一些东西在JDK或外部库中,可能导致改变实现(可能会创建一个新实现)。您的系统可能会发生变化,您需要在保留旧实施的同时添加新实施;一些维护等。

答案 20 :(得分:0)

我不想定义界面,除非我真的需要它。 IMO,界面是最滥用的设计模式之一。我认为你提到的案例是由于提出了“如果将来还需要......会怎样?”的问题。由于开发人员不是算命先生......我会坚持使用“使用不足”。

答案 21 :(得分:0)

将来稍后扩展的能力。

答案 22 :(得分:0)

当我们可能期望它被扩展时,为单个类创建接口可能有意义的一个例子(正如其他人所提到的那样)。

例如,如果我有一个我正在为个人使用而构建的跟踪工具,那将使用SQL服务器。我正在为DB抽象创建一个接口,即使DB方法包含在单个类中。原因是它将扩展应用程序以使用其他数据库平台更简单。

我意识到.NET框架中已经存在类似类型的抽象,但我认为这是一个相关的例子。

答案 23 :(得分:0)

有些人总是创建界面,因为它们可以自动生成,因此无论是否真正使用它们,它们都可以证明创建界面的工作时间是合理的。

例如,有时开发人员会根据编写的每行代码进行评估,因此使用interface是有意义的。

答案 24 :(得分:-2)

因为界面最适合明确指出类型