【问题标题】:Is there a benefit to having both an abstract class and an interface?同时拥有抽象类和接口有什么好处吗?
【发布时间】:2010-09-20 23:45:37
【问题描述】:

我从一个名为 ILogin 的通用接口开始。这些接口要求您实现两个属性:UserID 和 Password。我有许多实现此接口的登录类型类。随着我的项目越来越大,我发现许多类都重复了 UserID 和 Password 代码。现在我决定我需要一个基本的登录类。

创建一个实现 ILogin 接口的抽象基本登录类并让我的所有具体类仅从抽象类继承并在必要时覆盖是否合适?本来我以为这样不会有问题的。然后我开始认为 ILogin 可能是不需要的,因为它可能只会由我的抽象类实现。

同时保留抽象类和接口有什么好处吗?

谢谢!

【问题讨论】:

    标签: oop interface abstract-class ooad


    【解决方案1】:

    当然。让我们想一个具体的例子。

    假设我们有一个抽象类Animal。 比如说,我们创建了一些子类CatDogMosquitoEagle。我们可以实现它的Eat()Breathe()Sleep()抽象类Animal的方法。

    到目前为止,一切都很好。现在,假设我们想要为MosquitoEagle 类提供Fly() 方法。由于这两种生物的关系并不密切(一种是鸟,另一种是昆虫),因此很难为我们可以作为抽象类拥有的两种生物找到共同的祖先。这最好通过接口IFly 来实现。

    IFly 接口可以有一个Fly() 方法来实现。 MosquitoEagle 类都可以是抽象类 Animal 的子类,并实现接口 IFly 并且能够Eat()Breathe()Sleep()Fly() 没有某种类型两个阶级之间的奇怪祖先关系。

    【讨论】:

      【解决方案2】:

      我通常在有意义的情况下针对抽象类进行编码,并在每个类(抽象或非抽象)中实现(并在外部合同程序集/库中创建)一个接口,以便我可以更轻松地实现 Windows Communication Foundation 或inversion of control必要的(这几乎总是用于嘲笑)。这已成为我的第二天性。

      【讨论】:

        【解决方案3】:

        当然。接口始终是正确的方法——这样任何东西都可以实现它(包括已经有父对象的东西)。

        抽象类倾向于实现它,因此您不必重新实现该功能的某些部分。 Swing 使用了一点,它们将有一个接口,然后是一个默认实现,供您仅覆盖 5 种方法中的一种,或者它可能会为您添加侦听器,但您不必使用该基类,如果您不想。

        【讨论】:

          【解决方案4】:

          如果您的抽象类是实现接口的唯一类,那么您始终可以只检查抽象类的实例,您不需要接口。但是,如果您希望将来与尚未编写的新类兼容,这些新类不会扩展抽象类但可以使用接口,那么现在继续使用接口。

          【讨论】:

            【解决方案5】:

            我同意 cfeduke。我总是从接口开始,过去使用实现接口并提供基本功能的抽象类来促进从抽象类继承的类之间的代码重用。 Mocking 和 IOC 通常来说是依赖于接口的,仅出于这个原因,我会在我的设计中使用接口。

            【讨论】:

              【解决方案6】:

              如果抽象类具有功能,那么保留它是明智的。但是如果它只包含抽象方法而没有字段。我认为保留两者没有用。

              编辑:我处理带有大量抽象类的遗留代码。如果我有时间,我会添加接口,(并可能删除空的摘要)。因为使用接口极大地增加了可能性。他们通过精确定义接口来尊重他们的名字。

              【讨论】:

                【解决方案7】:

                您的界面定义了要被接受的对象必须履行的合同;您的抽象类定义了必须履行的契约并定义了一些具体的实现细节。

                这样想;如果您认为任何人都可能希望以不同于抽象类草拟的方式(例如,使用不同的支持数据类型实现)来履行该合同,那么您应该同时拥有接口和抽象类实现它。

                同时拥有抽象类和接口几乎没有开销;这种方法的风险主要涉及后来的编码人员遇到接口,没有意识到有一个实现接口的抽象类,并在不需要的地方从头开始创建整个实现。我想说这可以通过在你的接口文档中指定你的抽象类中有一个接口的“默认”实现来解决;虽然一些编码标准可能不赞成这种做法,但我认为它没有任何实际问题。

                【讨论】:

                  【解决方案8】:

                  我总是建议您使用接口。抽象类的优势在于您可以添加默认功能,但要求用户使用它们的单一继承是相当激进的。

                  在许多情况下,Microsoft 类库偏爱抽象类而不是接口,因为它使它们能够修改底层类。向抽象类添加方法很少会破坏从它继承的人。向接口添加方法总是会破坏其实现者。但是,这提供了使用接口的最佳理由之一:Microsoft 可能已经用完了您的一个继承。

                  不过,我建议在您的特定情况下,您可能希望重新审视您正在使用的设计模式。有很多“登录类型”类似乎很不寻常。

                  【讨论】:

                  • 所有登录类都有用户名和密码。更具体的登录类型(如sqllogin)会对此进行扩展,有database、approleid、approlepw、trustedconnection等。类型很多。
                  【解决方案9】:

                  我认为保留接口的好处是将来的类能够实现多个接口,而一个类只能从一个抽象类继承。

                  您可以通过创建具有不同方法集的新接口来扩展子类的功能。

                  【讨论】:

                    【解决方案10】:

                    假设你具体询问接口和抽象类何时具有相同的签名......

                    ...(如果接口的成员与抽象类的成员有任何不同,那么答案当然是肯定的,可能两者都需要)

                    ...但是假设成员是相同的,那么我能想到需要两者的唯一原因是,如果您在一个不允许多重实现继承的系统中编码,那么您的系统中有两个类需要多态相似,但必须从不同的基类继承...

                    【讨论】:

                      猜你喜欢
                      • 2011-07-14
                      • 2010-12-27
                      • 2012-11-22
                      • 2016-11-24
                      • 2010-11-23
                      • 2010-11-13
                      • 2013-02-17
                      相关资源
                      最近更新 更多