【问题标题】:Passing an interface instead of an object instance传递接口而不是对象实例
【发布时间】:2011-10-26 21:00:14
【问题描述】:

以 SqlBulkCopy.WriteToServer() 方法为例。其中一个重载将 IDataReader 作为参数。我的问题是,将接口传递给方法而不是对象实例本身有什么好处/优势?

http://msdn.microsoft.com/en-us/library/434atets.aspx

【问题讨论】:

  • 如果您想了解更多关于这种编程风格的理由,请查找关键字“多态性”。
  • 即使一个方法有一个IDataReader 参数,它仍然会得到一个对象实例......即实现该接口的任何类型之一。您不能将接口本身传递给方法(Type 对象除外)。
  • @stakx 所以基本上调用者方法将使用传递的对象,而不管接口在该对象实例中是如何实现的?

标签: c# .net oop interface


【解决方案1】:

对于一个接口,您可以有许多可能的实现。依赖于抽象(在这种情况下是接口)比依赖于实际的具体类更好——这可以带来更好的灵活性和可测试性。

这也将重点放在WriteToServer() 方法真正需要的东西上——它的契约唯一需要的是让调用者传入提供方法的具体类的任何实例/IDataReader接口声明的属性。

【讨论】:

  • 所以在 WriteToServer() 方法的背后,它正在调用 IDataReader 接口从传递给该方法的对象实例定义的方法(或多个方法)?
  • 这绝对有道理。我看到它增加了相当多的灵活性,并且不需要特定的类作为依赖项,尤其是使用 IDataReader 接口方法的许多类。
【解决方案2】:

传递接口意味着您可以传递实现该接口的任何对象,而不仅仅是一个特定对象。

这使代码更加灵活,因为它不必知道现在或将来可能实现接口的所有可能对象。

这也使它更加健壮,因为它只需要处理接口上众所周知和定义的属性和方法。

【讨论】:

    【解决方案3】:

    形参类型是接口类型——这意味着您可以传入实现此接口的任何对象(或者更确切地说,实现该接口的对象的实例)。

    你不是传入一个接口,你传入的是一个符合接口定义的契约的对象

    因此,如果您的数据源是 SQL Server,您将传递一个 SqlDataReader,如果是 Oracle,则传递一个 OracleDataReader

    您还可以实现自己的数据读取器并将其传递给函数,甚至编写一个模拟数据读取器来彻底测试该方法。

    这是众所周知的设计原则 - Program to an Interface, not an implementation

    来自 MSDN - When to Use Interfaces:

    接口是一种强大的编程工具,因为它们可以让您将对象的定义与其实现分开。

    【讨论】:

    • 给你的问题。假设您想使用抽象类而不是接口(只是为了论证)。您能否将抽象类作为方法的参数并传递继承该抽象类的所有子类?你为什么不这样做?顺便说一句,关于 Program to an Interface 的好文章,而不是实现。肯定会喝杯咖啡,然后享受剩下的阅读。
    • @Surfer - 是的,当然你可以在这种情况下使用抽象类。相同的参数集适用(我会说“程序是抽象,而不是实现”)。接口作为一种通信媒介更加明确,仅此而已。
    • 是什么让它们更明确?似乎来自没有实现的抽象类的方法与来自接口的方法相同。
    • @Surfer - 这个词......以及接口根本没有实现没有的事实(而抽象类可以有一些,通常是这样)。它是一个纯粹的契约,接口的用户不会期望或不需要查看代码来查找它是否实现了任何东西。
    【解决方案4】:

    当一个方法将其参数之一列为接口时,它并不是要求您传入该接口的实例(无论如何这是不可能的,您可以创建接口实例),而是要求您传入任何实现该接口的对象。

    例子:

    interface IMyObject {
        public void SomeMethod();
    }
    
    public class MyObject : IMyObject {
        public void SomeMethod() {
            // implementing code here
        }
    }
    

    您现在可以将 MyObject 的任何实例作为 IMyObject 类型的参数传递:)

    public class YourObject {
        public void DoSomething(IMyObject o) {
            // some code here
        }
    }
    
    YourObject yo = new YourObject();
    MyObject   mo = new MyObject();
    yo.DoSomething(mo); // works
    

    我希望这是有道理的!

    【讨论】:

      【解决方案5】:

      实际上,它希望您传递实现接口的类型的实例,而不是接口本身。

      当方法只关心接口声明的方法时,使用接口类型。只要对象实现了该接口,就可以在对象上调用其中定义的方法。

      【讨论】:

        【解决方案6】:

        这是接口的原因之一——在这个例子中,接口的所有消费者(即函数)关心的是它是否可以读取数据——它不介意它是来自SqlDataReader还是来自OleDataReader 或任何其他提供程序 - 替代方案将为每个可能的数据读取器提供几乎相同的单独重载(这当然是不切实际的,因为有人可能会为 dBase 或更奇特的数据库引擎提供一个)

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-09-14
          • 2016-06-05
          • 2022-01-06
          • 1970-01-01
          • 2022-11-21
          • 1970-01-01
          相关资源
          最近更新 更多