1

我阅读了很多关于 C# 的内容并进行了第一次实践练习,但我仍然是初学者,并且在尝试理解现有但尚未完成的 MVC 概念程序时有点迷失了方向。

我了解接口的用途以及我必须如何实现类或另一个接口的接口才能访问其包含的成员、函数等,但在现有代码中我发现了接口的另一种用途(在类的声明中):

  private IViewControl m_viewControl = null;
  private IModelControl m_modelControl = null;

这段代码不会出现在实现这两个接口的类中,而是出现在根本没有实现这两个接口的类中!

所以我的问题是:

  • 如何调用接口的这种用法?这显然不是接口的常规实现。
  • 通过这种使用界面的方式,我可以获得什么样的可能性?

非常感谢!

弯曲

请原谅我的英语,我不是母语人士。


嘿,

非常感谢大家的回答,甚至不能说哪个是最好的,因为所有的答案似乎都有帮助!我想我开始明白这是怎么回事了。

再次感谢!

4

9 回答 9

3

包含这些行的类

private IViewControl m_viewControl = null;
private IModelControl m_modelControl = null;

对实现这些接口的其他类有 2 个引用。所以回答你的第一个问题,这不是接口的实现,而是接口的使用。

回答您的第二个问题:这正是我们使用接口的原因。使用这些接口的类并不关心它们的实现。在您的开发过程中,您可以为其中一个或另一个编写一个虚拟实现,因为您现在不需要它,但您仍然可以运行和测试应用程序的其余部分。

另一个例子:让我们想象一下你想编写一个使用某个数据库的应用程序。将所有数据库逻辑放在接口后面。在您的应用程序的版本 1 中,您可能会使用 SQL 数据库。您写入数据库的类是否知道它是一个 SQL 数据库?不,他们不需要。因此,现在您继续前进并决定要使用不同的数据库系统。您只需更改接口背后的实现即可。

希望这可以帮助。

于 2013-10-16T12:55:41.097 回答
1

这是两个变量(实际上是成员变量,称为字段,因为它们是封闭类型的成员)。

它们可用于存储实现接口的任何项目,因此您可以将任何实现的内容IViewControl放入m_viewControl和任何实现IModelControl的内容中m_modelControl

于 2013-10-16T12:55:02.297 回答
0

这确实意味着,您可以分配给变量的对象必须实现接口。所以它必须是接口的类型。

于 2013-10-16T12:55:01.257 回答
0

接口基本上用于在不同的类之间实现类似的功能。仅当通过依赖注入需要它时,接口也用于创建类的对象。

例如:

Interface IMyClass{}
Class MyClass1:IMyClass
{
}

IMyClass obj;

因此,您可以将 obj 注册到IMyClass在一个类中实现的类(Bootstrapper),并通过构造函数或方法将 obj 注入到所有类中,而无需对其进行初始化。

因此接口防止不必要的对象创建从而防止内存泄漏,正如我上面提到的,它有助于以不同的方式在不同的类之间实现相同的功能。

于 2013-10-16T13:20:51.650 回答
0

听起来您没有正确掌握如何使用接口。让我用一个简单的例子来启发你:

class Driver{ 

     // A driver has two cars - they are cars, since they are 
     // of types (classes Bmw and Audi) that implement the interface ICar:
     ICar firstCar = MethodThatReturnsInstanceOfBmw(); 
     ICar secondtCar = MethodThatReturnsInstanceOfAudi(); 

     public void DriveAllCars(){

        // The interface ICar has a method "Start()", which both 
        // cars must therefor implement. The Driver class can call 
        // these methods, because it knows about them from the interface.
        firstCar.Start(); 
        secondCar.Start();
     }
}

该类Driver仍然不需要实现ICar - 只需了解它(对它有一个引用),因此它知道它可以用那种类型的“事物”做什么。然后它可以告诉汽车Start(),而无需向啮齿动物提供发动机实际工作的后部信息。

将其与现实世界进行比较:您无需成为汽车即可驾驶,也无需成为机械师 - 您只需要了解驾驶的基础知识,这些对于大多数汽车来说都很常见,尽管发动机和其他事情可能会有很大不同。

对通用功能的抽象协议,是接口的目的。

于 2013-10-16T13:06:33.420 回答
0

假设你有一个类,你不开发。你只是消费它。您知道它可以生成一些文件并将其作为文件流返回给您。你不知道它是如何产生的,你也不需要。您只知道它会返回一个文件流,然后您可以将其用于您自己的目的。为了实现它,您与该类的开发人员签订合同,该类应为您提供一个方法,该方法应返回一个文件流,并且该方法的名称应为 ReturnStream,例如。该合约称为接口。到该类的开发人员可以更改其文件生成逻辑时。但它仍然具有相同的名称 ReturnStream 并且它仍然会返回一个文件流。因此,您不必更改代码中的任何内容。

至于您的代码,您有两个 IViewControl 和 IModelControl 对象。您无需开发模型和视图。您只需使用其他开发人员的逻辑,他们使用接口实现编写类。你可以在你的代码中以你想要的方式使用它们。但是许多开发人员可以创建不同的类,这些类实现了 IViewControl 和 IModelControl 接口。您可以通过简单地更改实现接口的类实例来使用它们。

于 2013-10-16T13:03:29.750 回答
0

你在那里看到的东西叫做作文。这意味着您的类有两个字段是这些类型的实例,而不是它正在实现它们的接口。

让我们用汽车来做类比。“汽车”是一个非常通用的概念,所以让我们将其作为界面。某人拥有的 Toyota 是某个类的实例(例如:Corolla),而后者又实现了 Car 接口。另一方面,车轮是汽车的领域。您卡罗拉中的轮胎可能属于 Pirelli 类,该类实现了 Tire 接口。但是你的车不是轮胎——它轮胎。

接口是一种创建类型的方法,根本没有任何实现,但无法实例化。然后,您可以让其他类型实现该接口,为其赋予逻辑 - 因此您可以拥有该接口的许多变体,每个变体都以不同的方式做某事。关键是你要确保接口的所有实现者都有一组已知的方法签名和属性——你可能不知道它们是如何实现的,但你可以确定它们在那里。

如果您查看 C# 中的一些命名空间,它们有很多实现相同接口的类,您可能会更好地了解它们的行为方式。例如,System.Collections 中的许多类都实现了(令人惊讶的)ICollection接口。这可确保所有集合都具有例如Count属性和具有已知签名的CopyTo方法。

于 2013-10-16T12:59:38.633 回答
0

这种类型的用法非常适合限制特定对象的使用,或者编写可以在任意数量的类上工作的通用代码。假设我们有一个名为 Car 的类,它实现了一个名为 IDriveable 的接口:

public class Car : IDriveable

现在,在其他一些类中,我们可以轻松地实例化 Car 对象,如下所示:

Car myCar = new Car();

但是,如果 Car 类有几个我们不想在其他部分中访问的公共方法怎么办?或者我们想编写一个可以在任何实现 IDriveable 接口的类上工作的函数?相反,我们可以创建 IDriveable 接口本身的实例化,然后为其分配 Car,如下所示:

IDriveable myDriveable = new Car();

然后,如果下面的代码在 IDriveable 接口上工作,任何实现 IDriveable 的类都可以在它上面正常工作,例如这个例子:

private void TurnLeft(IDriveable vehicle)

PS你的英语使用得很好!

于 2013-10-16T12:59:58.607 回答
0

关于接口的重要一点是,您对它们是什么不感兴趣,而对它们能做什么感兴趣。因此,在这种情况下,您只对IViewControl分配给该局部变量的任何对象的元素感兴趣,因此它可以是任何实现的类,IViewControl并且很可能该类也可以做很多其他事情,但出于这些目的,事实这是IViewControl我们所关心的。

一个例子可能是我们有一个类对可以飞行的东西感兴趣,它不关心其他任何东西,所以我们创建了一个IFlyingThingIFlyingThing.Fly()方法调用的接口。然后我们可以有一个Bird, Plane,Butterfly和各种其他类型的实现IFlyingThing,我们可以将它传递给我们的类,它只会看到IFlyingThing并调用IFlyingThing.Fly()它可能是Bird.Fly(),或者Plane.Fly()它已经传递的实际对象。它不关心物体是什么,只关心它会飞。

Bird也可能实现IFeatheredAnimal,平面也可能实现,IHasJetEngines但我们的类只对IFlyingThing接口感兴趣,所以它不想或不需要知道这些。

这有助于我们避免将代码过于紧密地捆绑在一起,并使控制反转模拟对象等技术成为可能。

随着您学习 C# 的进步,您将大量使用接口。

于 2013-10-16T13:03:11.490 回答