我想我错过了“编程到界面”的概念

时间:2010-11-20 14:45:08

标签: c# interface

所以我对C#和使用接口仍然很新,当我认为我理解它们时,我意识到我并不完全。我发现我在寻求一些澄清的困惑是,当你创建一个接口,并且有一个继承自它的类

public Interface ISomeInterface
{
  //some methods/properties
}

public class FooClass : ISomeInterface
{
  //implemented ISomeInterfaces methods/properties
}

您在程序中的某个实现中使用此类对象

public class BarClass 
{
  private ISomeInterface _someInterface;
  public BarClass(ISomeInterface someInterface)
  {
    _someInterface = someInterface;
  }
  //rest of class
}

我的困惑是为什么我会这样设置它。我以为我会实例化一个类型为FooClass的新对象,并在构造函数中使用类型为FooClass的对象:

public class BarClass 
{
  private FooClass _fooClass;
  public BarClass(FooClass fooClass)
  {
    _fooClass = fooClass;
  }
  //rest of class
}

理解这一点我缺少什么?我不认为我会直接声明接口的对象?

提前致谢。

6 个答案:

答案 0 :(得分:7)

我们的想法是BarClass不应与ISomeInterface的具体实施紧密结合。

如果您使用此:

public BarClass(FooClass fooClass)

这意味着BarClass只能使用这个特定的FooClass实现,而不能用于任何其他实现。而如果您使用:

public BarClass(ISomeInterface fooClass)

现在BarClass已不再与FooClass紧密耦合。这意味着BarClass的使用者现在可以传递他想要的接口的任何实现,只要它遵守定义的合同(接口)。因此,如果他想要FooClass他传递FooClass的实例,但如果他对FooClass不满意,他可以编写自己的实现并将其传递给构造函数并从角度来看BarClass这是绝对透明的(不需要修改)。

类之间的弱耦合是OOP最基本的方面之一,因为它允许您轻松地将一个组件替换为另一个组件,而无需重写整个应用程序。

答案 1 :(得分:1)

假设FooClass向数据库写了一些东西。您想要测试BarClass而无需实际设置数据库。如果您创建了一个实现相同界面的不同TestFoo,您可以伪装成数据库并更轻松地测试您的类; BarClass不必知道它没有与'真正的'FooClass交谈。

答案 2 :(得分:0)

你有C / C ++背景吗?那你应该知道

private ISomeInterface _someInterface;

将写为

private:
  ISomeInterface& _someInterface;

在C ++中(假设你有一个名为ISomeInterface的抽象基类)。

这意味着您存储对实现ISomeInterface的对象的引用,而不是这样的对象本身。这样做的好处是你可以将任何对象传递给实现ISomeInterface的BarClass,这样可以提供更大的灵活性,例如:用于单元测试。

答案 3 :(得分:0)

通过使用接口定义而不是具体实现,您的代码现在更加松散耦合。该技术用于依赖注入。

此外,当您需要以不同方式实现FooClass时,这会派上用场。如果您使用了具体实现,则需要在声明FooClass的位置更改代码。针对界面进行编程可以保护您免受此类更改的影响。

答案 4 :(得分:0)

编程到ISomeInterface而不是FooClass的一个主要好处是,您可能可能会更改FooClass的实现。例如,考虑一个数据库驱动的博客应用程序:

interface IBlogStorage{
    getPosts();
}

然后你有一个类:

class XMLBlogSotrage: IBlogStorage{}

并假设您实现了界面的所有内容。稍后,您认为XML太慢而您想使用RDBMS,然后:

class MsSQLBlogStorage:IBlogStorage{}

在这种情况下,您无需更改其他代码中的任何内容,只需创建一个新类并将其插入即可!那些已经存在的代码,不需要打扰存储在哪里。

答案 5 :(得分:0)

另一种思考接口和类之间相互作用的方法是颠倒它们。这意味着首先从课程开始。假设您有几个类公开了一个名为“Sort()”的方法。然后你有另一个类,它有一个方法需要引用这些类,然后调用它们的“Sort()”方法。您可以创建并附加这些类的接口,而不是使用具有不同参数的多个方法(非常快速,因为这些类已包含实现)。

 A.Sort()
 B.Sort()
 C.Sort()

 interface ISortable {void Sort();}
 A : ISortable
 B : ISortable
 C : ISortable

 D.SortSomething(ISortable foo)
 {
      foo.Sort()
 } 

也许这太抽象了。我最喜欢使用接口是让我的类能够参与foreach循环。

 class SomeCollection : IEnumerable
 {
      List<SomeItem> _items = new List<SomeItem>();

      // This is the only code I need to enable this class to participate in foreach loop.
      public Enumerator GetEnumerator()
      {
            return _items.GetEnumerator();
      }
 }

一旦发现接口如何简化代码,您甚至可以在编写类之前开始创建接口。