关于Java:接口的目的

The purpose of interfaces continued

好吧,我认为接口是一种强制对象实现一定数量功能的方法,而不必使用继承。有点像合同。我半明白他们的意思。

但是,如果界面中的所有内容都是:

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

它没有这样的实现,那么无论谁使用您的接口,每次都必须从头开始编写它。

如果您创建了许多类,所有这些类都实现了这些特性,并且实现只是略有不同,那么这将是一项非常艰巨的工作。

我很感激你帮我解决这个问题,因为我知道这很重要。


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

假设您创建了一个类Animal。所有的动物,包括人类,都是如此。每一种动物都继承了诸如吃、呼吸等常见的方法。

但是现在假设你有一个MathProblem类。您希望有一些类可以通过将问题传递给solve(MathProblem problem)方法来解决这个问题。你知道,一个Human,也可以一个Computer,可以解决这个数学问题。所以他们都需要能够解决这个问题。你也许可以让计算机扩展一些拥有这个方法的MathSolver类,但是人类已经扩展了动物,并且不能扩展其他任何东西。因此,一个更好的方法是使MathSolver成为一个接口,让HumanComputer和任何其他需要解决问题的类都实现该接口。

还请注意,HumanComputer可能以完全不同的方式解决问题,因为它们的对象不同。这就是接口的最佳用途。定义跨越多个继承层次结构的某些功能,这些功能可以有非常不同的实现,但都可以传递给接受它们中任何一个的方法。想想Comparable接口;它不是某类对象所拥有的东西,所有种类的东西都可以比较,而且通常以非常不同的方式。但是你总是可以调用一个ListComparable对象的sort,因为你知道它们有一个特定的顺序,不管它们是NumbersAnimalsComputers或其他什么(只要它们实现Comparable并定义它们的顺序)。


比起继承,更喜欢组合。通过这种方式,您可以在一个类中实现(比如eat(),该类作为数据成员被合并到所有动物中。只写一次,重用它,但不能以一种方式将一种功能显式绑定到另一种功能。

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


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


您应该将接口视为行为的权威声明,它首先与实现问题无关。

如果您想避免代码重复,那么可以结合使用接口使用抽象基类。在这里,您可以实现可能在所有接口实现类中重复的所有内容,否则。

H.T.BR/>托马斯


一般化

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

标准化

接口允许为实现它的所有子类设置标准化。它指定了子类必须具有的"什么",但不强制它应该具有的方式。

100%提取

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

去耦合(松耦合)

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

多重继承

通过使用接口,我们可以实现使用类不可能实现的MI。


还有旧线,我知道。但我刚刚读到"接口是Java中创建多重继承的唯一方法"。这是非常错误的,因为委托(或者卡尔所说的"复合")是获得多重继承的唯一方法(记住:"委托就是继承",几乎是这样)。

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

实际上,您并不需要接口来创建一个工作程序,它们只是没有任何功能或功能代码的助手。顺便说一句,托马斯对抽象类的看法非常正确,这些抽象类远比接口重要,因为这就是您可以从中获得可重用代码的地方。

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


使用接口更多的是为使用代码提供一种了解您期望从中得到什么的方法,而不是您需要关心使用代码的细节。

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

由于我们的业务层(BL)程序集将与数据访问层(DAL)程序集直接通信,因此DAL无法与BL直接通信。如果DAL希望使用对象而不是单个字段,会发生什么?您必须定义自己的DAL对象,并使用刚刚收到的输入对其进行水合物处理。基本上,更多的工作,更多的资源消耗,以及多个表示相同数据的对象,这使得维护成为一场噩梦。

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

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

[编辑]如果有很多对象可以做类似的事情,那么使用可重写/虚拟方法组合接口和基类可能比仅使用接口更有用。


If you are creating a number of classes all implementing such features and the implementation is only slightly different, this is going to be a lot of hard work.

在这种情况下,您可以很容易地在类的层次结构中创建另一个层,实现Animal,但对于以某种方式吃东西的所有动物来说,它是一个祖先类。

1
2
3
4
5
6
7
8
class Herbivore implements Animal {
  public void eat(Object food) {
   ...
  }
}

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

允许您使用super.eat()覆盖eat,只更改小部分。

您应该同时期待代码重用和组件封装。然后,如果你的接口真的不能描述类本身,而仅仅是它的一个组件,你可以按照卡尔·马纳斯特的建议进行组合。


是的,您需要随时实现它,但是您可以每次都不同地实现它,任何调用它的类都不需要担心它是如何实现的。

例如,如果您有一个动物园对象,其中包含一组动物(new tiger()、lion()、bear()),那么您的动物园可以为某个集合a.eat()中的每一个动物a执行该操作,它将起作用。动物园不在乎有三种不同类型的动物以完全不同的方式进食。


一个主要原因是,您可以使用接口引用(类似于抽象方法)创建对象。当您这样做时,每个实现接口的对象都可以分配给它。例如,如果狗和车都是可清洗的,那么您可以这样做:

可清洗WD=new dog();

可洗厕所=新车();

如果washable具有public abstract方法wash(),则可以执行以下操作:

WD。

WC.WAW();

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

有关更详细的解释,请参阅此处:http://www.artima.com/objectsandjava/webuscrit/polymorphisminterfaces1.html


这并不是一个真正的答案,只是一个我认为在考虑接口时有用的例子,而是考虑需要该方法的接口Comparable

1
public int compareTo(T anotherObject)

用户可以随心所欲地实现这一点。例如,如果一个Person implements Comparable,比较可以基于姓氏,然后是名字,忽略大写。或者,它可以根据用户想要的年龄等来决定。实现这个接口是非常有用的,因为它允许用户使用像Collections.sort()这样的东西,这些东西要求要排序的元素需要具有可比性(否则如何进行比较?)


你想得倒过来了。不是首先考虑实现,而是首先考虑行为(如方法签名所描述)。然后在基类中实现适当的行为,从而提供更灵活、可扩展的系统。您很快就摒弃了"契约式设计",但它是一个关键的设计策略,也是Web服务、SOA等的基础。


and it has no implementation as such
then whoever uses your interface has
to write it from scratch..every time.

接口的每个实现都可以是不同的。关键是您可以在不知道实现的情况下使用接口。举个例子:

1
2
3
4
public interface ILogger
{
    void WriteMessage(string message);
}

您的应用程序可以使用ILogger接口来记录错误/调试信息等,但不管如何实现记录器,它可以是FileSystemLoggerDatabaseLogger或任何其他实现。因此,您可以在任何时候替换实现,而不必更改提到日志记录的代码中的所有位置。