【问题标题】:The importance of interfaces in Java [closed]Java中接口的重要性[关闭]
【发布时间】:2013-05-26 16:10:32
【问题描述】:

假设我们有两个类,TigerAeroplane。 这两种类型的共同点是速度。我知道创建超类ClassWithSpeed 然后从中派生子类AeroplaneTiger 是不合逻辑的。 相反,最好创建一个包含方法speed() 的接口,然后在AeroplaneTiger 中实现它。我明白了。但是,我们可以在没有接口的情况下做同样的事情。我们可以在Aeroplane 中定义方法speed(),在Tiger 中定义方法speed()。 唯一(可能是非常大的)缺陷是我们无法通过接口引用“访问”TigerAeroplane 的对象。

我是 Java 和 OOP 的初学者,如果有人向我解释接口的作用,我将不胜感激。 干杯!

【问题讨论】:

  • 听起来你已经发现了一个非常重要的“缺陷”......
  • 你可以有一个方法getCurrentSpeed(InterfaceWithSpeed) 并称之为getCurrentSpeed(new Aeroplane())getCurrentSpeed(new Tiger())
  • 这个问题很可能与programmers.stackoverflow.com有关。
  • 你已经正确地理解了为什么我们有接口。您能否更清楚地说明问题到底是什么?
  • @RyanRansford 正确的链接是programmers.stackexchange.com

标签: java interface


【解决方案1】:

是:

public int howFast(Airplane airplane) {
    return airplane.speed();
}

public int howFast(Tiger tiger) {
    return tiger.speed();
}

public int howFast(Rocket rocket) {
    return rocket.speed();
}

public int howFast(ThingThatHasntBeenInventedYet thingx) {
    // wait... what? HOW IS THIS POSSIBLE?!
    return thingx.speed();
}

...

public int howFast(Mover mover) {
    return mover.speed();
}

现在,想象一下将来必须返回并更改所有这些 howFast 函数。

接口与否,每个类都必须实现或继承speed() 方法。接口使您可以更轻松地使用这些不同的类,因为它们都承诺以某种方式运行。您将调用speed(),它们将返回int,因此您不必为每个可能的类编写单独的方法。

当您发现由于相对论物理学的突破而需要以不同方式处理速度时,您只需更新调用speed() 的方法。当您的曾孙女为HyperIntelligentMonkeyFish 编写课程时,她不必反汇编您的古老二进制文件并进行更改,以便您的代码可以监视和控制她的突变军队。她只需声明HyperIntelligentMonkeyFish implements Mover

【讨论】:

  • +1 - “Mover”这个名字比我的“IObjectWithSpeed”好,而且你的代码很有说明性。
  • 一个接口不提供实现,所以你仍然需要单独更改速度函数......
  • 请参阅“策略模式”以进一步了解此示例;其中 Tiger 可以使用 PodalMoverStrategy 而 Airplane 可以使用 AirborneMechanizedMoverStrategy
  • 超智能猴子鱼。还有一个曾孙女。多么漂亮的例子。
  • 应该说你应该只在有需要并且有意义的时候才添加接口。不要为所有方法创建接口以防万一:p
【解决方案2】:

接口允许 Java,因为它是静态类型的,在语言设计者认为值得的程度上解决多重继承限制。

在动态语言(如 Python、Ruby 等)中,您可以在任意对象上调用 speed 方法,并在运行时发现它是否存在。

另一方面,Java 是静态类型的,这意味着编译器必须同意该方法将提前存在。在不共享共同祖先并且可能只有共同对象的类上执行此操作的唯一方法是接口。

由于对象可以实现任意数量的接口,这意味着您可以获得多重继承的好处(单个对象可以为不同的方法构成多个不同的对象)而没有缺点(两个超类中的冲突实现) .

对于 Java 8,该语言的设计者得出结论,没有任何实现的接口过于严格(我猜他们不喜欢 my solution ;-)),因此他们允许默认实现,从而扩展了多接口的继承选项,同时仍然试图通过a complex set of precedence rules避免冲突的实现问题,以便有一个明确的默认实现来执行。

【讨论】:

  • 回复。多重继承位,您能否更新它以解决 Java 8 的新接口默认实现以及与之相关的快速失败方法?
【解决方案3】:

我试图用下面的例子来解释接口的优点-

假设您有另一个类需要使用老虎或飞机作为参数。所以通过使用接口你可以调用使用

someObject.someMethod(ClassWithSpeed)

但是如果你不使用接口你可以使用

someObject.someMethod(Tiger)
someObject.someMethod(AeroPlane)

现在你应该怎么做?你可能的答案是,"I will use two overloaded method".

到目前为止还可以,但是

假设您需要添加更多选项(例如汽车、自行车、兔子、乌龟……还有 100 个其他选项)。那么您将如何更改现有代码?你需要改变很多东西..

上面的整个示例只有一个目的。也就是说

“我们需要接口来创建更好、可重用和正确面向对象的接口 设计”

注意

  1. 如果您确定程序太小并且您永远不需要更改它们,那么我认为没有接口也可以实现

【讨论】:

  • 那么,唯一的好处是我们可以拥有可以引用实现该接口的各种对象的接口引用?
  • 总体的主要优点是,可移植性,可重用性
  • 如果你使用接口,你仍然需要在每个类中进行更改,接口不提供实现......
  • @anana.. 是的 .. 我添加了超类的 :D.. 而不是界面的优势 .. 只是再次编辑.. 感谢您指出
【解决方案4】:

定义接口允许您定义不仅适用于 Airplane 和 Tiger,而且适用于共享相同接口的其他类的方法。

例如,假设您的接口是 IObjectWithSpeed。然后你可以定义一个这样的方法——在一个对 IObjectWithSpeed 对象进行操作的类中。

  public double calculateSecondsToTravel( IObjectWithSpeed obj, double distance ) {
       return distance / obj.getSpeed();
  }

接口允许我们满足open/closed principle - 对扩展开放,对修改关闭。不需要修改上述方法的单个实现,因为定义了实现 IObjectWithSpeed 的新类。

【讨论】:

  • 是的,但是我们可以在每个类中实现 speed()。我们不节省时间和空间,因为在界面中我们没有定义函数。
  • 但是有了一个接口,您可以在一个类中定义 speed() —— 即,一个不实现 IObjectWithSpeed 的类。
【解决方案5】:

我想深入了解更多理论细节,但会尝试使用此示例进行解释。

考虑 JDBC API。它是用于处理 Java 中与数据库相关的选项的 API。现在,行业中有这么多的数据库。如何为此编写驱动程序?好吧,快速而肮脏的方法可能是使用我们自己的类和 API 编写自己的实现。

但是从程序员的角度思考。他们会在使用不同数据库的同时开始学习DATABASE DRIVER的API吗?答案是否定的。

那么问题的解决方法是什么?只要有一个定义明确的 API,任何人都可以为自己的实现进行扩展。

在 JDBC API 中,有一些接口,如 Connection、ResultSet、PreparedStatement、Statement 等。现在每个数据库供应商都会实现该接口,并为此编写自己的实现。结果 ? :减少了开发人员的工作量并且易于理解。

现在,这个自定义实现可能包含什么?这很简单。他们做什么,以 ResultSet 接口为例并实现它,并以任何方法返回 ResultSet,返回 实现的类 像这样的 ResultSet 接口

结果集 rs=new ResultSetImpl(); //这是他们在内部做的。

所以接口就像合约。它们定义了您的类能够做什么,并为您的应用程序提供了灵活性。您可以正确使用接口创建自己的 API。

希望对你有所帮助。

【讨论】:

    【解决方案6】:

    接口不仅仅是一个方法签名。

    它是一种代表合约的类型。合同是事情,而不是方法签名。当一个类实现一个接口时,是因为有一个共享行为的契约,该类有兴趣将其实现为一个类型。该契约是通过指定的成员实现的,这些成员通常是方法体,但也可能包含静态最终字段。

    老虎和飞机可能都可以表示为具有通过 speed() 实现的共同行为的类型......如果是这样,那么接口代表表达该行为的合同。

    【讨论】:

      【解决方案7】:

      除了描述这些类的功能外,接口的方法可以在不了解实现它的类的情况下使用,即使对于尚未定义的类也是如此。

      因此,例如,如果您需要一个类Transport 来计算高效路由,则可以给它一个实现ClassWithSpeed 作为参数的类,并使用它的方法speed() 来计算它需要什么。这样,您可以将它与我们的类 Aeroplane 一起使用,也可以与我们稍后定义的任何类一起使用,例如 Boat。 Java 会注意,如果你想使用一个类作为Transport 的参数,它将实现ClassWithSpeed,并且任何实现ClassWithSpeed 的类都实现方法speed() 以便可以使用它。

      【讨论】:

        【解决方案8】:

        编译器使用接口(作为一种语言构造)来证明方法调用是有效的,并允许您让依赖类与实现类交互,同时尽可能少地了解实现类。

        【讨论】:

          【解决方案9】:

          这是一个非常广泛的问题,可以给出一个简单的答案。我可以推荐一本书Interface Oriented Design: With Patterns。它解释了接口的所有功能。以及为什么我们不应该避免它们。

          【讨论】:

            【解决方案10】:

            您是否尝试过使用组合来代替?如果我希望 2 个不同的类继承相同的能力,我会使用一个类,该类通过使用抽象类并检查实例来获取其工作类型的对象。接口对于强制将方法包含在类中很有用,但不需要任何实现,也不需要 2 个编码人员团队在不同的编码领域工作。

            Class Tiger {
              public MovingEntity mover;
            
             public Tiger(){
            
              mover.speed=30;
              mover.directionX=-1;
              mover.move(mover);
            
             }
            
            }
            Class Plane {
              public MovingEntity mover;
            
             public Plane(){
              mover.speed=500;
              mover.directionX=-1;
              mover.move(mover);
            
             }
            
            
            Abstract Class Moverable(){
              private int xPos;
              private int yPos;
              private int directionX;
              private int directionY;
              private int speed;
            
            
            Class MovingEntity extends Moverable {
             public void move(Moverable m){
               if(m instanceof Tiger){
            
                  xPos+=directionX*speed;
                  yPos+=directionY*speed;
            
               }else if(m instanceof Plane){
                  xPos+=directionX*speed;
                  yPos+=directionY*speed;
            
               }
             }
            

            【讨论】:

              【解决方案11】:

              在语言级别上,接口的唯一用途是,就像您提到的那样,能够以一种通用的方式引用不同的类。然而,在人员层面上,情况却有所不同:IMO Java 在设计和实现由不同的人(通常来自不同的公司)完成的大型项目中使用时非常强大。现在,系统架构师无需在 Word 文档上编写规范,而是可以创建一堆类,然后实现者可以直接将这些类插入到他们的 IDE 中并开始处理它们。 换句话说,它更方便,而不是声明“X 类实现方法 Y 和 Z,以便将其用于目的 A,只是说“X 类实现接口 A”

              【讨论】:

                【解决方案12】:

                因为创建界面为您提供Polymorphism,涵盖所有这些类,即 Tiger 和 Aeroplane。

                当基类的功能也将成为子类功能的核心时,您可以从(抽象或具体)类扩展。

                除了核心功能之外,您还想为类添加增强功能时,您可以使用接口。因此,即使它不是您类的核心功能(因为您已经通过实现接口签订了合同),使用接口也会为您提供多态性。与为每个类创建 speed() 方法相比,这是一个巨大的优势。

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2015-03-11
                  • 2017-04-29
                  • 1970-01-01
                  相关资源
                  最近更新 更多