接口的目的仍在继续

时间:2010-10-29 14:10:11

标签: java oop interface

好的,所以我认为接口是一种强制对象实现一定功能的方法,而不必使用继承。有点像合同。我半看到了他们的观点。

但如果界面中只有:

 public interface animal{
  void eat(object food);
}

并且没有这样的实现,那么每次使用你的界面的人都必须从头开始编写它。

如果你要创建一些所有实现这些功能的类,并且实现只是略有不同,这将是一项艰苦的工作。

任何帮助我理解这一点都是值得赞赏的,因为我知道这非常重要。

13 个答案:

答案 0 :(得分:20)

接口是在Java中创建多重继承的唯一方法。

假设您创建了一个班级Animal。包括人类在内的所有动物都延伸到这一点这些动物中的每一种都继承了常见的方法,如吃,呼吸等。

但现在让我们说你有一个MathProblem课程。 并且您希望通过将问题传递给solve(MathProblem problem)方法来使某些类可以解决该问题。 而且你知道Human,还有Computer可以解决数学问题。所以他们都需要能够解决这个问题。您可能能够让计算机扩展一些具有该方法的MathSolver类,但Human已经扩展了Animal,并且无法扩展其他任何内容。因此,更好的方法是使MathSolver成为一个接口,同时具有HumanComputer和任何其他需要解决问题的类来实现它。

另请注意,HumanComputer可能会以完全不同的方式解决问题,因为它们具有不同的对象。这就是接口最适合的。定义跨越多个继承层次结构的某些功能,并且可以具有非常不同的实现,但是都可以传递给接受其中任何一个的方法。想想Comparable界面;它不是特定类别的对象所具有的东西,所有类型的东西都可以进行比较,并且通常以非常不同的方式进行比较。但是,您始终可以对List ComparableNumbers个对象进行排序,因为您知道他们有某个订单,无论他们是AnimalsComputers,{{1或其他任何东西(只要它们实现Comparable并定义它们的顺序)。

答案 1 :(得分:4)

Prefer Composition over Inheritance.这样,你可以在一个类中实现(比方说)eat(),这个类作为数据成员被合并到你的所有动物中。写一次,重用它,但是不能将一种功能明确地绑定到另一种功能。

如果你有两种(或十种)不同的饮食方式,你可以根据需要换掉它们。

答案 2 :(得分:3)

您正在混淆接口和继承。它们是不同的概念,可以相互补充。如果所有的eat方法只是略有不同,那么你可以创建一个包含公共代码的基类,并通过覆盖方法从子类中调用它们来添加不同的部分。基类仍然可以实现接口。希望很清楚。

答案 3 :(得分:2)

您应该将接口视为权威的行为声明,这与实施问题无关。

如果要避免代码重复,则将抽象基类与接口结合使用。然后,您可以实现所有可能在所有接口实现类中重复的内容。

HTH。
托马斯

答案 4 :(得分:1)

是的,你需要永远实现它,但你可以每次都以不同的方式实现它,任何调用它的类都不需要担心它是如何实现的。

例如,如果你有一群动物的Zoo对象(新的Tiger(),Lion(),Bear())那么你的动物园可以为某个集合a.eat()中的每个Animal a做一次。将工作。动物园并不关心有三种不同类型的动物以完全不同的方式进食。

答案 5 :(得分:1)

  

如果你要创建一些所有实现这些功能的类,并且实现只是略有不同,这将是一项艰苦的工作。

在这种情况下,您可以轻松地在您的类层次结构中创建另一个层,该层实现Animal但是对于以某种方式进食的所有动物的祖先类,例如

class Herbivore implements Animal {
  public void eat(Object food) {
   ...
  }
}

class Cow extends Herbivore..
class Horse extends Herbivore..

您可以使用eat覆盖super.eat()并仅更改轻微部分..

你应该同时期待代码重用和组件封装。那么如果你的界面真的没有表征类本身,而只是它的一个组成部分,你可以按照Carl Manaster的建议进行组合。

答案 6 :(得分:1)

使用接口更多的是为消费代码提供一种了解您对它的期望的方式,而不是需要关注消费代码的细节。

例如,我们在业务层/数据访问层中使用接口的方法之一。

因为我们的业务层(BL)程序集将直接与数据访问层(DAL)程序集通信,所以DAL无法直接与BL通信。如果DAL想要使用对象而不是单个字段会发生什么?您必须定义自己的DAL对象,并使用刚刚收到的输入对它们进行水合。基本上,更多的工作,更多的资源消耗,以及代表相同数据的多个对象,这些都会导致维护噩梦。

但是,如果您在DAL中定义接口,您可以告诉消费者DAL的期望。然后,您可以在BL中实现这些接口,并传递接口的实例而不是BL对象。

接口都是关于抽象出实施细节,而这些细节并非绝对必要。

[编辑] 如果你有很多做类似事情的对象,那么接口和带有overridable / virtual方法的基类的组合可能比仅仅接口更有用。

答案 7 :(得分:1)

老线程,我知道。但我刚才读到“接口是在Java中创建多重继承的唯一方法”。这是非常错误的,因为委托(或像Carl所说的“compositon”)是获得多重继承的唯一方法(记住:“委托是继承”,好吧,差不多)。

您只需要接口告诉开发人员“嘿,不要忘记委派这个或那个类”!接口仅作为正确委托(或通常:实现)的提醒,但它们不能继承任何代码。根本不需要多继承接口。

实际上,你并不需要创建工作程序的接口,它们只是没有任何功能或功能代码的助手。 Btw Thomas对抽象类非常正确,它们比接口更重要,因为那是你可以从中获取可重用代码的地方。

通常,当我编写一个java应用程序时,我只在最后创建接口,作为未来程序员的帮助。或者我根本不创建任何接口; D

答案 8 :(得分:1)

概括

使用JAVA接口,我们可以实现跨子类的泛化。泛化意味着这里具有相同行为的子类以不同的方式实现。

<强>标准化

接口允许为实现它的所有子类设置标准化。它指定子类必须具有的“内容”,但不强制它应具有的内容。

100%抽象

接口体提供100%抽象,因此子类不应该错过任何抽象方法的实现。如果我们使用抽象类,这是不可能的。

去耦合(松散耦合)

在开发应用程序时,与最终用户交互的代码可以通过使用接口松散地耦合到服务器[B L C]上运行的代码。

多重继承

使用接口我们可以实现使用类无法实现的MI。

答案 9 :(得分:0)

  

它没有这样的实现   那么谁使用你的界面了   从头开始写它...每次。

界面的每个实现都可以不同。关键是你可以在不知道实现的情况下使用接口。考虑一下例子:

public interface ILogger
{
    void WriteMessage(string message);
}

您的应用程序可能会使用ILogger界面来记录错误/调试信息等。但记录器的实现方式无关紧要 - 它可以是FileSystemLogger,或DatabaseLogger,或者任何其他实施。因此,您可以随时替换实现,而无需更改提及日志记录的代码中的所有位置。

答案 10 :(得分:0)

你正在考虑倒退。 首先考虑行为(如方法签名所述),而不是首先考虑实现。然后,您可以在基类中实现适当的行为,从而提供更灵活,可扩展的系统。 您很快就驳回了“按合同设计”,但这是一项关键的设计策略,也是Web服务,SOA等的基础。

答案 11 :(得分:0)

这不是一个真正的答案,而是一个在考虑接口时我觉得有用的例子,但想想需要方法的接口Comparable<T>

public int compareTo(T anotherObject)

用户可以根据需要实现此目的。例如,如果Person implements Comparable<Person>,则比较可以基于姓氏,然后是名字,忽略大小写。或者它可以基于年龄等。但是用户想要。实现此接口非常有用,因为它允许用户使用Collections.sort()之类的东西,这些东西要求要排序的元素需要具有可比性(如何进行比较?)

答案 12 :(得分:0)

一个主要原因是您可以使用接口引用创建对象,类似于抽象方法。执行此操作时,可以为其分配实现接口的每个对象。例如,如果Dog和Car都实现了Washable,那么你可以这样做:

可洗wD =新狗();

可洗wC =新车();

如果Washable有公共抽象方法wash(),那么你可以这样做:

wD.wash();

wC.wash();

将调用它们各自的方法。这也意味着您可以接受一个接口作为方法的参数,这意味着您不必添加不必要的代码来处理实现某个接口的每个类。

请点击此处查看更详细的说明:http://www.artima.com/objectsandjava/webuscript/PolymorphismInterfaces1.html