.NET接口解释

3
我知道在.Net中接口定义了一个接口与继承它的类之间的契约。最近我刚刚完成了一个大量使用接口作为数据访问层的项目,这让我想到……这有什么大不了的呢?当我需要添加一个新方法到DAL时,我必须在接口中创建方法签名,并将其添加到继承接口的类以及DAL中,从而增加了"额外的工作"。那么接口有什么大不了的,而且为什么我要为自己创造额外的工作呢?

这是许多其他类似问题中的一个副本,例如https://dev59.com/dXVD5IYBdhLWcg3wAGiD。 - jason
这是 Interfaces: Why cant I seem to grasp them? 和许多其他问题的重复。此答案有意标记为社区维基。 - jason
11个回答

9
接口有什么大不了的? 一旦你定义了契约,就可以更换实现而不必担心破坏代码的其余部分。
考虑这样一种情况:你有一段使用.NET中的List<T>的性能差劲的代码。如果你使用List<T>的硬实现,很可能会通过改变实现来破坏更多的代码。
如果你使用IList<T>或者IEnumerable<T>,你可以将List<T>替换为LinkedList<T>(或任何实现你选择的接口的类型)并在一个地方解决问题,而不是必须触及所有的代码。
最后...这与多态有关。

3

在我看来,接口与类不同的重要之处在于,接口不像类那样被绑定到特定的继承层次结构中,因此它们比类更加灵活,可用于实现抽象接口。使用接口而不是具体类使得系统耦合度更低。更改实现很容易:只需提供任何其他实现所需接口的类即可。


3
如果你有两个类,两个不同的数据访问层类,具有不同的实现方式(可能是SQL Server和CouchDB),那么拥有一个标准接口(它们都实现)意味着你有一种与这些类交互的标准方式。你将能够“热插拔”不同的数据类,并且不需要知道具体的底层实现。

2

使用接口的一个原因是可以在类之间创建松散的耦合。

例如,如果你在类构造函数中传递一个接口而不是实际的类,你将允许更松散的耦合。因为任何人都可以继承该接口并实现自己的实现。


2
        foreach (object obj in myArray)
        {
            // distroy all IDisposable objects
            if (obj is IDisposable)
                (obj as IDisposable).Dispose();

            // ends initialization of all ISupportInitialize objects
            else if (obj is ISupportInitialize)
                (obj as ISupportInitialize).EndInit();
        }

因此,如果一些不同的对象实现了相同的接口,那么该接口保证每个对象都有一些共同的方法,这些方法在接口中描述。

这在对象集合中非常有用。您知道所有的动物(包括人类)都可以吃东西。因此,如果您在汽车上有动物,它们每个人都可以吃,无论是人、老鼠还是斑马...

所以接口IEatable :)...


1

在我上学的时候,我并没有理解接口或者迭代器的美妙之处,因为我们尝试解决的问题可以不使用抽象化方法就用一半的代码量完成。

总的来说,软件模式是由行业真正需要而产生的。我想接口在某个时候被认为几乎是一种模式。

由于时间限制,学校项目所能教授的知识是有限的。


0

通过使用接口,我可以使我的代码更具可测试性。

如果我有一个ManagerClass

public class PersonManager
{
  public PersonManager(IPersonRepository repository)
  {
    this.Repository = repository;
  }
  private IPersonRepository Repository{get;set;}

  public Person ChangeUsername(string username)
  {
    Person person = this.Repository.GetByUsername(username);
    person.Username = username;
    this.Repository.Save(person);
    return person;
  }
}

发布代码将使用一个存储库对象,该对象将调用数据库,但是对于我的单元测试,我希望隔离对数据库的依赖性,以便我可以创建一个实现我的接口的模拟存储库:
public class MockPersonRepository : IPersonRepository
{
   public Person GetByUsername(string username)
   {
      return new Person();
   }
   public void Save()
   {}
}

当我编写单元测试时,我可以传入模拟对象:

[Test]
public void ChangeUserName_NewUsername_ExpectUpdateUsername()
{
  //Arrange
  var manager = new PersonManager(new MockPersonManager());

  //Act
  Person person = manager.ChangeUsername("bob");

  //Assert
  Assert(AreEqual("bob", person.Username);
}

我现在已经测试过,我的ChangeUsername方法已经更新了用户名,同时没有与数据库通信


0
如果您更改数据存储方式,只需创建一个实现DAL接口的新类,即可立即在应用程序中使用。您无需查找应用程序中所有使用实例并将旧类替换为新类。
例如,您还可以使用IoC(借助Castle Windsor或其他库的帮助)通过配置插入特定的数据访问风格,而无需重新编译应用程序。

0
在你的例子中,当你只有一个类实现接口时,你看不到它的好处。如果你有10个类都实现了这个接口,你会立刻看到它的优势。
如果你有一个IFoo的集合,你可以把任何实现IFoo接口的类放进去,并在每个对象上调用相同的Bar()方法。每个实现它的类中,Bar()方法的实现可能会非常不同。

0
简单来说,接口用于在两个组件之间提供一个清晰的分离点。与设计一个组件以针对单一类型(如 List<T>)不同,您可以设计为针对接口(IList<T>)工作,并能够使用实现该接口的任何对象进行工作。
当您开始使用依赖注入和模拟测试时,这种分离非常有用。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接