【问题标题】:Difference between a Pure Abstract class and an Interface [closed]纯抽象类和接口之间的区别[关闭]
【发布时间】:2012-03-18 20:33:46
【问题描述】:

我正在与一位同事讨论,他坚持认为在 Java 和 C# 等语言中,没有任何理由使用纯抽象基类,因为它只是意味着您无法解决缺少多重继承的问题.

我觉得他在这点上是错误的,因为我一直认为一个事物如果是名词就是宾语,如果是动词就是接口。

例如,如果我想定义类型 Bird,我想在其中强制执行 fly 方法而不实现它,那么我会将其设为纯抽象类。

如果我想定义一个类型Flies,我会将其作为fly方法的接口。

Bird 可能实现Flies

我错了吗?

编辑:

我能给出的唯一有力的论据来支持我的观点是,在未来的某个时候,设计可能需要改变,以便鸟类可以吃东西。如果所有的鸟都吃同样的东西,那么这需要添加到Bird,使其非纯抽象。

如果Bird 是一个接口,那么这个更改简直就是一场噩梦,因为我不知道从其他基类继承的东西是否也实现了我的Bird 接口,所以我不能只是重构我的问题.

【问题讨论】:

  • +1 - 好问题,我认为在抽象类用例的未来答案中将探讨许多合理的原因。
  • 只是回答您问题的部分(因此没有发布答案):我不会说接口总是动词lot 使用接口来允许一个类向世界展示一个最适合作为名词建模的世界。看看java.util中的一些接口:Comparator,Enumeration,List,Iterator,Map,...
  • 意见就像背面,每个人都有一个,有些人比其他人更好。我不认为将 OOP 与语法进行比较是正确的,但它很接近。
  • 为了扩展这个类比,我会说接口是形容词而不是动词。接口描述了一个对象拥有的功能,抽象类描述了一个类的层次结构。
  • C#中的抽象类到底是什么?

标签: c# java oop


【解决方案1】:

不久前我读到了一些与此相关的东西。它基本上说,如果项目链接在一起,那么使用抽象类。如果它描述了某物的属性,则使用接口。

因此,使用您的示例,鸟将是一个抽象类,因为您希望鹰或鹦鹉从同一个地方派生。

如果您只想要“传单”之类的东西,那么您可以将其设为接口,因为鸟类、飞机和其他事物可能会实现该接口,但它只是它们共同的一个属性。

要考虑的另一件事是,在某些时候,您可能想要为您的鸟实际放置一些具体的方法。毕竟所有的鸟儿都以同样的方式飞行,所以你可能希望班级在鸟儿飞行时打印“襟翼襟翼”。如果您使用的是接口,则需要在每个类上执行此操作(或然后引入新的基类),而如果您首先使用了抽象类,则只需在一个地方添加行为。

【讨论】:

    【解决方案2】:

    假设您有一个插件系统,其中包含多个插件类型,每个插件类型实现不同的接口。

    现在,假设您正在使用反射在运行时查找这些插件类。

    由于它们是接口,一个插件可以是多种类型的插件。

    如果您将每个插件类型设为抽象类,那么您可以控制继承层次结构并确保每个插件都是不同的类型。

    所以纯抽象类和接口是有区别的。它不是您需要使用的,但 ++、递归甚至对象也不是。

    【讨论】:

      【解决方案3】:

      除了您的第一次编辑,即未来的一些要求。一种可能的用例是声明一个常量并在抽象类中对其进行初始化。

      import java.util.ArrayList;
      import java.util.List;
      
      
      public abstract class AbstractPure implements ISomeInterface {
          public static final List<String> days = new ArrayList<String>();
          static{
              days.add("Monday");
              days.add("Tuesday");
              days.add("Wednesday");      
              days.add("Thursday");   
              days.add("Friday"); 
              days.add("Saturday");   
              days.add("Sunday"); 
          }
      }
      

      【讨论】:

      • 从技术上讲,这不再是一个纯粹的抽象类了......
      • 我个人认为接口中的常量通常是一个设计问题——至少是原语和枚举无法处理的所有问题。但这是一个有效的观点,接口是不可能的。
      • @zmbq:是的。从技术上讲,纯抽象与接口相同,这在现实世界中毫无意义,对我来说也不是。我的答案只是在你有常量并且你想要初始化它的接口方面进行讨论。上面的代码 sn-p 可以很容易地写成class Days { List&lt;String&gt; days = new ArrayList(); ....},然后在任何接口中使用这个类作为常量。取决于开发者喜欢它的方式。
      • @Voo:见我最后的评论。甚至除了原语和枚举之外的东西也可以以合理的方式处理:)
      • 就目前而言,days 是可变的,并且可能不是一周中几天的最佳设计决策,因为它是恒定的。
      【解决方案4】:

      我能想到至少一个很好的理由:您可以稍后扩展抽象类,而不会破坏向后兼容性:假设一个类/接口

      abstract class/interface Foo {
          void foo();
      }
      

      如果我们使用一个接口,我们现在可以肯定地知道永远无法向 Foo 添加额外的功能。这可能会导致类似interface Foo2 implements Foo

      另一方面,如果您有一个抽象类,您可以轻松地向它添加另一个方法,只要您提供一个基本实现即可。

      请注意,Java8 将允许接口做基本相同的事情 - 这对于希望更新其库以使用 lambdas 而不必破坏与已编写的数百万行代码的兼容性的库编写者很有用。

      【讨论】:

      • 这也是我能想到的唯一原因。换个说法:你怎么知道什么时候不需要额外的实现功能?什么时候肯定是接口?我是否应该永远不要使用界面,因为我可能需要为其添加一些功能?
      • @sji 最后是一个取决于实际业务案例的判断电话,所以除了显而易见的事情之外,我没有看到太多可以帮助我们的东西。至少在 Java 中还有一个事实是没有多重继承。 Java8 允许接口具有方法的默认实现应该有很长的路要走,以使这一点更加清晰。
      【解决方案5】:

      我会说接口和类都定义了对象。正如您自己所说的那样,动词转到方法-它们是这些对象的属性。在你的fly示例中,我将声明一个接口FlyingCreature并在其中定义一个方法fly(因此你有ComparableSerializable之类的接口,而不是SerializeCompare。你有方法compareTo) .还有关于你的另一个例子 - 鸟:如果你没有任何关于鸟的逻辑,那么你将它声明为接口。

      接口用于声明不同类型对象将具有的共同属性,它们按分类对它们进行分组。后记,使用您知道它们具有相同接口的事实,您将能够以相同的方式处理它们。

      我没有看到纯抽象类有什么好处,因为我已经说过抽象类和接口都声明对象。

      【讨论】:

      • 我已经扩展了我的问题,指出了将鸟类作为界面的潜在缺点。
      【解决方案6】:

      我对纯抽象类进行了一些搜索(自从我上次使用 C++ 以来已经有一段时间了),我能找到的唯一用例是在 C++ 中定义接口(它没有接口)。

      所以我想说,如果你可以使用纯抽象类,你还不如使用接口,就像你朋友说的那样。

      但是,我从来没有遇到过在 C# 中需要纯抽象类,所以这可能是一个假设性问题。

      【讨论】:

      • 我确实来自 c++ 背景,这可能会影响我对此的思考,我再次扩展了这个问题以说明对抽象基类的潜在需求。
      • 是的,但是你怎么知道哪个接口突然要吃东西了?
      猜你喜欢
      • 1970-01-01
      • 2011-04-07
      • 1970-01-01
      • 2014-01-20
      • 1970-01-01
      • 1970-01-01
      • 2023-03-03
      • 2011-04-04
      • 2011-01-06
      相关资源
      最近更新 更多