【问题标题】:Understanding Interfaces in OOP了解 OOP 中的接口
【发布时间】:2013-02-08 00:49:54
【问题描述】:

我正在努力学习高级别的 OOP 概念。我正在阅读主题界面并且感到困惑。但首先,让我告诉你究竟是什么导致了这种混乱。
我测试了这个Code Sample。但我对接口的使用感到困惑。在实现该代码之后,在我看来,我可以通过简单地创建一个实例来从类 A 中调用方法 DoFirst。那么为什么首先使用接口呢?

类似这样的:

A myA = new A();
myA.DoFirst();

同样,

B myB = new B();
myB.DoFirst();

在这两个类中,我都必须实现一个名为“DoFirst”的方法,那么接口对我有什么好处?

我不能自己在不同的类中编写这些方法吗?

我的第二个问题,假设我有一个有 5 个方法的接口。如果一个类实现了它,并且只想提供 3 个方法的实现,而不是编写接口提供的所有 5 个方法的代码。这不是没用吗?为什么有我不想要的访问方法?

有人可以用例子回答这些吗(非常感谢)?

【问题讨论】:

  • 我看到接口的好处之一是允许模拟对象实现以支持为尚未编写的代码编写单元测试。我还帮助团队协调,所以如果我希望你创建一个执行 X Y 和 Z 的对象,我可以模拟它直到你完成你的实现,这让我可以继续我的工作,直到你完成你的工作。同样在第二种情况下,我将为 5 种方法和 3 种方法创建不同的接口。省略某些方法一定是有原因的吧?
  • 看看您链接中的第一个答案,它实际上回答了您所关心的问题
  • 请一次只问一件事。对于两个问题,创建两个单独的 SO 问题(如果它们相关,请插入链接)。
  • 是的,但是您可以查看abstractvirtual 类型,接口的想法是确保一个类实现其中的所有类。再次参考我的例子;这会使我的课程使用的代码崩溃
  • 最简单的可能答案:当您需要在外部引用代码时使用接口,该代码在实现它的每个类中应该有不同的行为。

标签: c# oop interface


【解决方案1】:

您提供的链接中已经指出了优势... 基本上你也可以写

void DoSomething(IMyInterface obj)
{
    obj.DoFirst();
}

然后将实现该接口的任何类型的对象作为参数发送。

A myA = new A();
DoSomething(myA);
B myB = new B();
DoSomething(myB);

方法DoSomethig 不关心对象的类型,只要它公开一个名为IMyInterface 的接口。

【讨论】:

  • 你的回答对我来说很有意义。你说得这么简单。谢谢
【解决方案2】:

一些现实生活中的例子 - 也是使用接口的另一种方式/原因。

在我自己的代码中,我有一个引擎,它处理代码以在 Excel 中生成报告。在这个引擎中,我必须以两种不同的方式编写代码,一种使用 Microsoft Excel Interop,另一种使用 Open Office Interop。我没有复制我的整个引擎以两种不同的方式工作,或者在所有实际的互操作函数中编写大量 if 语句,而是实现了一个接口。然后我声明了两个类,每个类都实现了接口,但是一个使用Excel,另一个使用open office。然后,在我的代码中,我简单地引用了接口及其函数,并在函数的最开始使用一个 if 语句来告诉接口要实现哪个类。

public class ExcelEngineInterop : ISSinterface
{ ... }

public class OOEngineInterop : ISSinterface
{ ... }

//cant use two variables with the same name, so use 1 interface reference instead
ISSinterface ssInt;
if(ExcelFlag)
    ssInt = new ExcelEngineInterop();
else
    ssInt = new OOEngineInterop();

//two VERY different functions between Excel and OpenOffice.
ssInt.OpenApp();
ssInt.OpenFile(fileName);

//etc etc and so on

这是使用接口的另一个原因。当您需要一个代码块根据某些外部标志执行两种(或更多)不同的方式时。

另一个例子。

有一个顶级表单,其下有许多自定义用户控件。用户触发表单级事件,例如按钮单击,但根据哪些用户控件处于活动状态以及单击发生时它们的设置,控件本身需要做一些不同的事情。与其编写大量的 if 语句来确保每个语句从顶层正确运行,不如在每个控件上实现一个接口,然后执行以下操作:

public ButtonClick(object sender, EventArgs e)
{
    //note: I dont know which of my classes currentrightcontrol belongs to at the moment.
    //      it could be any one of 22 different controls. It must be cast to something
    //      in order to call the ButtonClick method (its actual type is generic "UserControl"

    IMyRunControl ctrl = CurrentRightControl as IMyRunControl;
    ctrl.FormButtonClicked();
}

【讨论】:

  • 很好的解释……说得通
  • 这是一个很棒的答案,但再说一遍,您在没有使用接口的情况下创建了这两个类。现在使用 flag 和 If 条件,你能不能得到同样的结果?
  • 其实,你是对的.. 如果我按照我的方式去做,那真的很难。你在那个例子中是对的。 if(ExcelFlag) ExcelEngineInterop ee = new ExcelEngineInterop();否则 OOEngineInterop oo = new OOEngineInterop();那么我需要另一个 IF 检查,如果 ee==null && oo != null 然后执行此操作。而且这张支票会走很长一段路……我说对了 Nevyn 吗?
  • 正确。如果您在该级别有两个不同的类,则在每个地方都需要完全相同的开关或 isNull 检查,引擎需要使用这些类的功能之一。使用该界面,我能够消除引擎代码中的 150 if 语句。这似乎无关紧要,直到您记住循环的数量。通过使用界面 =D,我计算了每次运行平均减少 3000 次操作
  • 每次运行 3000 次,(取决于报告)每次报告 1 到 500 次“运行”......这可以显着提高速度。更少的操作意味着更快的代码。此外,当您开始涉足此类事情时,您会发现铸造对象(装箱/拆箱)和其他类似事情的成本,而使用界面可以让您远离或至少大大降低。
【解决方案3】:

C# 是一种静态类型语言(至少除非你明确告诉它不是)。这意味着编译器使用变量的类型来知道被引用的对象是否有你将要使用的成员。

因此,该接口为编译器(以及其他程序员)提供了一个约定,该类实现了该接口。因为接口可以在没有层次关系的类之间共享,这意味着您可以通过在参数类型中定义该接口来定义一个可以将对象作为参数的方法。

【讨论】:

  • 如果您能举个例子来支持您的回答,我会更容易理解。
猜你喜欢
  • 2010-11-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-12
  • 2018-12-09
  • 2016-03-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多