【问题标题】:Need for Abstract Class as well as Interface?需要抽象类和接口?
【发布时间】:2010-09-24 06:57:07
【问题描述】:

接口是一个 100% 的抽象类,因此我们可以使用接口进行高效编程。有没有抽象类比接口更好的情况?

【问题讨论】:

    标签: java interface abstract-class


    【解决方案1】:

    当您确实打算创建具体类时使用抽象类, 但要确保所有子类中都有一些共同状态 或某些操作的可能通用实现

    接口不能包含任何一个。

    【讨论】:

    • 我会继续定义接口,即使定义一个抽象类。它使您的代码对测试更友好,并且与特定实现的耦合更少。
    • 是的,当然,我 100% 同意。在我的代码中,我通常将接口分解为接口(听起来很傻),并使用抽象类作为标准实现和状态的基础。
    • 您说:“并使用抽象类作为标准实现和状态的基础您可能的意思是:”并使用抽象类作为“通用实现”和状态的基础”跨度>
    • @Shwa:我的错。我应该多注意我的cmets。
    • 我只会添加注意,即使使用通用实现,也始终写入接口的约束。我确实看到很多代码,即使将变量声明为接口类型,也会根据抽象类的工作做出假设。
    【解决方案2】:

    是的,抽象类和接口都有一席之地。

    让我们举一个具体的例子。我们将研究如何从抽象的AbstractBankAccount 中创建CheckingAccountSavingsAccount,并了解如何使用接口区分这两种类型的帐户。

    首先,这是一个抽象类AbstractBankAccount

    abstract class AbstractBankAccount
    {
        int balance;
        public abstract void deposit(int amount);
        public abstract void withdraw(int amount);
    }
    

    我们的账户余额为balance 和两个必须由子类实现的方法depositwithdraw

    正如我们所见,一个抽象类声明了应该如何定义银行账户的结构。正如@Uri 在他的回复中提到的,这个抽象类有一个状态,即balance 字段。这对于接口是不可能的。

    现在,让我们将AbstractBankAccount 子类化为CheckingAccount

    class CheckingAccount extends AbstractBankAccount
    {
        public void deposit(int amount)
        {
            balance += amount;
        }
    
        public void withdraw(int amount)
        {
            balance -= amount;
        }
    }
    

    在这个子类CheckingAccount 中,我们实现了两个抽象类——这里没什么有趣的。

    现在,我们如何实现SavingsAccount?它与CheckingAccount 的不同之处在于它会引起兴趣。使用deposit 方法可以增加利息,但话又说回来,并不是客户自己存入利息。因此,如果我们有另一种将钱存入帐户的方法,专门用于利息,例如accrueInterest 方法,可能会更清楚。

    我们可以直接实现SavingsAccount中的方法,但是将来可能会有更多可以产生利息的银行账户类型,所以我们可能想做一个InterestBearing接口,它有accrueInterest方法:

    interface InterestBearing
    {
        public void accrueInterest(int amount);
    }
    

    所以,我们现在可以通过实现InterestBearing 接口来创建一个可以引起兴趣的SavingsAccount 类:

    class SavingsAccount extends AbstractBankAccount implements InterestBearing
    {
        public void deposit(int amount)
        {
            balance += amount;
        }
    
        public void withdraw(int amount)
        {
            balance -= amount;
        }
    
        public void accrueInterest(int amount)
        {
            balance += amount;
        }
    }
    

    现在,如果我们要创建另一种类型的帐户,比如PremiumSavingsAccount,我们可以创建AbstractBankAccount 的子类并实现InterestBearing 接口来创建另一个计息帐户。

    InterestBearing 接口可以看作是为不同的类添加了一个共同的特性。当支票账户没有产生任何利息时,如果有一个功能来处理支票账户的利息,那就没有意义了。

    因此,确实存在抽象类和接口在一种情况下共存和协同工作的地方。

    【讨论】:

      【解决方案3】:

      Abstract class v/s interface 是一个让 Java 新手和想要深入研究的人产生很多好奇心/兴趣/困惑的话题。

      This article 提供了有关该主题的详细说明。

      【讨论】:

      • 您提供的链接非常有用。它清楚地使用了抽象和接口。
      【解决方案4】:

      您可能更喜欢无实现的抽象类而不是接口的原因有几个:

      • 可以在编译时捕获某些不可能的强制转换和 instanceof 操作。
      • 您可以选择在以后的版本中添加具体方法。
      • 多年前曾经有显着的性能优势。
      • 从高度模糊的安全角度来看,您无法通过创建预先存在的类和抽象类的子类来获得预先存在的类来实现方法。

      但另一方面,interface Java 关键字允许更清晰的源代码。

      【讨论】:

      • 谢谢朋友。您对我的查询提出了宝贵的意见。
      【解决方案5】:

      一般来说,接口描述了您的代码应使用的公共 API,而抽象基类最好作为实现细节保留,其中可以保留通用代码或状态,以减少任何实现类中的重复。

      通过在您的 API 中使用接口,人们(包括您)可以更轻松地针对您的类编写测试代码,因为您可以使用不依赖任何外部资源的测试类,或者在现实生活中难以模拟的明显类型的不良但难以模拟的行为。

      因此 java 提供 List 接口和 AbstractList 抽象基类以“最小化实现”接口所需的工作量......

      【讨论】:

        猜你喜欢
        • 2011-02-11
        • 2017-11-15
        • 2017-02-19
        • 2014-04-12
        • 1970-01-01
        • 1970-01-01
        • 2011-04-17
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多