【问题标题】:Is it a good/common practice to use abstract classes in polymorphism in Java? [closed]在 Java 的多态性中使用抽象类是一种好的/常见的做法吗? [关闭]
【发布时间】:2013-11-20 12:05:33
【问题描述】:

在我看到的所有示例中,接口都用于实现多态性。现在我们有了下面的抽象类代码

AbstractClass parent = new Child();

Here那个人说

一个常见的论点是多态性只适用于接口和 不是抽象类。

我认为他的意思是它们通常是用于 Java 多态性的接口。我看到很多人发现他的问题很傻,想要 URL。这是我发现的here。所以我的问题是在 Java 中使用多态性中的抽象类是一种好的/常见的做法(如我的示例中 - 因为多态性是非常广泛的定义)?

【问题讨论】:

  • 提供的链接错误。很容易争论您应该大多数多态性使用接口,但显然在某些情况下通用基类(无论是否抽象)是最佳解决方案。

标签: java oop polymorphism abstract-class


【解决方案1】:

关于您的问题,没有这样的观点认为使用多态是一种不好的做法,在适用的地方使用它是一种很好的做法,但这取决于您将类的要求定义为纯虚拟又名的用例接口。

【讨论】:

    【解决方案2】:

    最好使用符合合同的最通用的父级;如果接口定义了您需要的所有函数签名,则使用它们而不是实现该接口的抽象类。 Bill Venners 与 Erich Gamma 讨论的文章 Design Principles from Design Patterns 进行了详细介绍。

    【讨论】:

    • 只是补充一点,例如,您可以使用 (java.util) AbstractList list = new ArrayList()。但是,使用List 接口会更好,因为您可以轻松地将实现更改为LinkedListCopyOnWriteArrayList,而不会影响其他代码。 LinkedListCopyOnWriteArrayList 不是 AbstractList 的子类。通过在接口可用时使用抽象类,会使未来的重构变得复杂。
    • @blalasaadri 感谢您抽出宝贵时间。您能解释一下“在 Java 中,当您向接口添加新方法时,您会破坏所有客户端”?我不明白这一点。我们有两个类,一个客​​户端和一个服务器。服务器实现接口。如果所有客户端都按照之前的界面工作,为什么我们会破坏所有客户端?
    • @brettw 感谢您抽出宝贵时间。你能回答同样的问题吗?
    • 这可能是指当您更改接口时,所有实现类也必须更改以适应新接口。如果您有一个客户端和一个服务器都使用相同的接口(嗯,实现该接口的类),您将不得不修改两者。但是,如果您更改了实现,但它仍然适合接口,它仍然可以像以前一样使用。
    【解决方案3】:

    根据我的经验,抽象类总是包含某些接口的部分实现。例如,EJB 就是这种情况。它是一种更好的设计,可以将 API 及其实现分开,甚至是部分实现。所以我建议做一个接口和一个抽象类。但是对于引用使用接口而不是抽象类。

    【讨论】:

      【解决方案4】:

      答案取决于您的上下文。

      例子:

       // Abstract class template
      abstract class AbstractFirst {
        public void doSomething(){
          this.doOne();
          this.doSecond();
          System.out.println("");
          System.out.println("Test");
        }
         public abstract void doOne();
         public abstract void doSecond();
      }
      
      // Concrete implementation
      class ConcreteFirst extends AbstractFirst {
         public void doOne(){System.out.print("One"); }       // must be implemented
         public void doSecond(){System.out.print("Second"); } // must be implemented
      
         public static void main(String[] args){
             ConcreteFirst cf = new ConcreteFirst();
             c.doSomething();
         }
      }
      

      这会打印出来

      OneSecond 
      Test
      

      到控制台。这对于接口是不可能的。这种模式称为“模板方法模式”,是 GoF 模式之一

      【讨论】:

      • 我认为问题是指将对象声明为抽象类的实例,即AbstractFirst af = new ConcreteFirst();,而不是是否应该使用接口而不是抽象类。
      【解决方案5】:

      一般来说,是的。使用必要的最少特定类型始终是一种好习惯。这也适用于具体的超类,而不仅仅是抽象类和接口。

      public class MyClass{} // not an interface and not abstract
      public class SubClass extends MyClass{}
      
      public class OtherClass{
          public MyClass getMyClass(){
               return new SubClass();
          }
      ]
      

      在实践中,这取决于情况。如果一切都包含在一种方法的范围内,那真的没关系。

      public void doStuff(){ // void method, so never going return any details
         AbstractFoo foo1= new ConcreteFoo();
         // no better than
         ConcreteFoo foo2 = new ConcreteFoo();
         // because nothing external to this method will ever know 
      }
      

      但是,让开发人员总是使用最不具体的实现(或接口)的原因只是为了养成习惯。

      【讨论】:

        【解决方案6】:

        它们的最佳用途之一是您在“孩子”之间有共同的行为。

        你的界面

        interface Drawable{
            void paint();
        }
        

        具有通用代码的抽象类

        abstract class AbstractRectangularObject implements Drawable{
        
            public void paint(){
                 paintVertices();
                 //your code to fill body
            }
        
            //Abstract method that all subclases needs to implement
            protected abstract void paintVertices();
        
        }
        

        你真正的子类

        class Rectangle extends AbstractRectangularObject {
             protected void paintVertices(){
                 //code to pain vertices
             }
        }
        

        -

        class RoundRectangle extends AbstractRectangularObject {
             protected void paintVertices(){
                 //code to pain vertices
             }
        }
        

        【讨论】:

          【解决方案7】:

          如果你有共同的功能和属性在子类之间共享,同时类本身太抽象而不能有实例,使用抽象类将是一个好习惯。如果没有,我会更喜欢使用接口。

          【讨论】:

            猜你喜欢
            • 2019-05-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2016-08-18
            • 1970-01-01
            • 1970-01-01
            • 2012-10-12
            • 2010-12-22
            相关资源
            最近更新 更多