怀疑使用界面?

时间:2010-02-15 06:14:38

标签: oop interface

每当我听到界面时,我都有以下疑问。

我有以下界面

interface Imammals
          {
           walk();
           eat();
           run();
          }

我有两个实现此界面的 Human Cat 类。

无论如何,这两种方法的功能在两个类中都会有所不同。

对于Eg: walk(),功能不同,因为猫使用四条腿而人类使用两条腿

然后,为什么我需要一个只能声明这些方法的通用接口?我的设计在这里有问题吗?

如果方法的功能在两个类中都相同,我可以选择基于类的继承,其中父实现完整功能,子继承并使用父类方法。

但是这里的接口可以帮助我们整合方法声明,还是还有更多内容?

编辑: walking(),吃(),running()更改为walk(),eat(),run()和哺乳动物更改为Imammals。

14 个答案:

答案 0 :(得分:3)

在您的场景中,类型继承或接口实现都可以工作 - 但基于接口的抽象允许现有类型模型的外部类型提供功能。它可能是一个模拟对象,或者它可能是某种超级杀手机器人,可以走路跑步和吃但不是真正的哺乳动物(所以它从<{1}} 继承上课可能令人困惑或只是不可能)。

特别是,接口允许我们巧妙地表达这种关系,同时避免C#中具有单一(类型)继承的微妙点。

答案 1 :(得分:2)

使用界面,您可以拥有以下内容:

   public void walkMyAnimal(Animal animal) {
       animal.walk();
   }

无需知道究竟是什么动物通过了。

答案 2 :(得分:2)

接口允许您定义继承类的行为,因此如果您将来有Donkey,那么您只需实现此接口并确保您的驴步行,跑步和吃饭。

如果你的某些对象有共同的行为,你也可以使用合成而不是具体实现。

阅读一些关于战略模式的信息,我认为这会有所帮助。

答案 3 :(得分:1)

接口的一大优势是,即使在Java和C#等语言中,不允许多重继承,类也可以使用多个接口。例如,某些东西可以是Closable和List,但不能从两个(假设的)抽象基类AbstractClosable和AbstractList继承。

它也适用于您正在编写库或插件接口并希望为代码提供使用库用户或插件编写器提供的对象的方法,但您不希望(也不应该)在实施中有任何发言权。例如,可以考虑使用Java中的Listener接口。没有这些,就不可能有事件模型,因为Java不支持回调。

通常,接口适用于需要具有特定功能的对象的情况,但实现功能的方式可能差异很大,并且可能不是类的唯一事物。 / p>

答案 4 :(得分:1)

你想要一个界面的原因是在命令它们时能够同样对待它们。

无论谁叫步行()(这是一个相当奇怪的名字顺便说一句,它应该是步行())只是想告诉你的动物这样做。实际的实现会有所不同,但这不是调用者会关心的事情。

答案 5 :(得分:1)

嗯,有时候你想要能够做一些“能够跑步的东西”而不必在设计时知道你是在谈论人类还是猫或其他什么。例如,想象一个函数mammal raceWinner(mammal m1, mammal m2){...} 计算哪些哺乳动物会在比赛中获胜。要确定谁获胜,可能需要调用m1.running()m2.running()。当然,我们传入的哺乳动物真的是猫或人类或其他什么,这个类提供了running()的实际实施。但所有raceWinner需要知道的是,他们有running()方法,并且具有预期的签名。

如果我们仅在running()cat上定义human,则无法调用m1.running()(因为编译器无法保证m1具有running() m1方法,因为它只知道它是mammal实现raceWinner(human m1, cat m2))。因此,我们必须实施一个{{1}}同样适用于我们想到的两个人,两只猫或任何其他哺乳动物,这导致我们做了更多的工作。

答案 6 :(得分:1)

界面提供合同。它没有提供实现。将课程界面化是一种很好的做法。

答案 7 :(得分:0)

当然,walking()eating()在不同的动物中会有不同的实现。但他们都是walkrun等等。这就是界面所说的。

答案 8 :(得分:0)

您可以使用继承对此进行建模,这将允许您为部分或全部方法提供默认实现。但是,接口对于声明适用于许多不相关类型的一组功能非常有用。

要继续您的示例,您可以想象一个类型Alien,它可能具有相同的方法,但不适合您的继承层次结构。

答案 9 :(得分:0)

接口的目的是告诉你什么一个类,而不是 它做什么。

这对于接受以不同方式工作的东西尤其重要 - 我们连接到PC的每台打印机的工作方式不同,每台扫描仪也是如此,每个外部驱动器也是如此。如果所有程序都需要关心每个程序是如何工作的,那么对于每个出现的打印机型号,您都需要重新编译,例如,Microsoft Office。

答案 10 :(得分:0)

开发接口的一种方法是定义一个接口和一个相对类,它以一种通用的合理方式实现te接口。既有接口又有类,你可以在类alreay派生自另一个类的情况下使用接口,否则一个类可以派生到接口实现。

这并不总是可行,但它解决了很多问题。

使用公共接口仅使用接口来使用不同的对象(例如,将它们收集到通用列表中)。

答案 11 :(得分:0)

如果您只有一个基本类型,那么完全抽象的类和接口之间没有太大区别。接口不能有任何实现代码,但抽象类可以。在这种情况下,抽象类可以更灵活。

接口真正有用的地方是您可以为单个实现分配多个接口,但是您只能分配一个基类。

例如,您可以:

class Cat : IMammal, IFourLeggedAnimal
{
}

class Human: IMammal, ITwoLeggedAnimal
{
}

现在你可以用“walk()”方法将它们视为哺乳动物,或者你可以将它们视为四条腿或两条腿动物(不一定是哺乳动物)。

答案 12 :(得分:0)

对于像哺乳动物这样的界面真正有用的是,当你想让它们走路,吃饭或跑步时,你可以将对象(人类和猫)的数组视为相同的类型

例如,如果您创建的游戏中您有一个数字(对象将动态创建,但只是例如让10只猫和1个人)在屏幕上显示(保存在集合中),并且只是想要他们每次都要走路,你可以这样做:

foreach(mammals m in MamalsArrayList){
{
    m.walking();
}

注意:我建议您遵循命名约定并在其前面用“I”命名您的接口,因此您的示例应命名为IMammals。

无需知道天气,任何特定的m都是猫或人。

界面很难在任何特定的片段中显示 - 但是当你真的需要它时,你可以看到它们有多么有用。

当然他们有其他用途(在其他答案中提到),我只关注你的例子。

答案 13 :(得分:-1)

这里有两个经常混淆的问题。继承行为允许以相同的方式响应不同的“命令”,例如Man.walk()=== Woman.walk()。多态行为允许以不同方式响应相同的“命令”,例如Animal.move()对于一个对象的Animal.move()可能与另一个对象不同,当slug滑动时,它会选择飞行。

现在,我认为其中第二个是好的,而第一个则不是。为什么?因为在OOP中我们应该将功能封装到对象中,这反过来又促进了代码重用以及OOP的所有其他优点。因此,我们应该将其委托给共享对象,而不是继承行为。如果您了解模式,那么这就是州和战略正在做的事情。

问题在于,通常在您继承时,您将这两种行为混合在一起。我认为这比它的价值更麻烦,我们应该只使用接口,尽管有时我们必须使用框架提供的任何东西。

在你的具体例子中,Mammal可能是一个糟糕的界面名称,因为它并没有真正告诉我它的作用,它有可能爆炸成千上万的方法。将接口划分为非常特殊的情况更好。如果您正在为动物建模,您可能有一个Moveable界面,其中包含一个方法move(),每个动物都可以通过步行,跑步,飞行或爬行来适应这些方法。