首页 文章

继承:使用基类或派生类来做东西[关闭]

提问于
浏览
3

这是一个关于应该使用继承方式的简单问题 .

考虑到我必须提供业务逻辑来打印'foo'和'bar'并且我有两个类的层次结构:一个具有仅打印'foo'的方法和另一个首先扩展并具有打印'bar'的方法 . 在这两个类中,我有一个名为 necessaryMethod() 的方法,负责调用那些打印'foo'和'bar'的方法 .

我用两种方法实现它的方式:

第一种方法是让基类做一些事情,派生类利用它 . 第二种方法是让基类不做任何事情(只提供实现)并将所有责任放在派生类上 .

请考虑以下代码:

Approach 1:

public class A{

    protected void necessaryMethod(){
        callFoo();
    }

    protected void callFoo(){
        System.out.pritln("foo");
    }       
}

public class B extends A{

    @Override
    protected void necessaryMethod(){
        super.necessaryMethod();
        callBar();
    }

    protected void callBar(){
        System.out.println("bar");
    }   
}

public class FooBarClass{
    public static void main(String args[]){
        B b = new B();
        b.necessaryMethod();
    }
}

Approach 2:

public abstract class A{

    protected abstract void necessaryMethod();

    protected void callFoo(){
        System.out.pritln("foo");
    }       
}

public class B extends A{

    @Override
    protected void necessaryMethod(){
        calFoo();
        callBar();
    }

    protected void callBar(){
        System.out.println("bar");
    }   
}

public class FooBarClass{
    public static void main(String args[]){
        B b = new B();
        b.necessaryMethod();
    }
}

哪种方法对于代码的可维护性和可读性是很好的(在大型软件产品/大类层次结构的上下文中;这只是一个例子)?

(这是一个通用的编程问题 . 我没有征求意见 . )

2 回答

  • 1

    暂时离开编程的技术方面,某些行为(其方法)有助于定义它 . 即一只狗吠() .

    一般问题是:

    • 行为callFoo()是否会让你想到'A'(A类)或'B'?

    1.1 . 在定义类时,在编程之外的类中组织方法(行为) .

    Large Code Bases

    尽管B可能属于现实世界中A的集合,但有时过多的继承可能会导致代码导航和维护 . 继承的目的更重要,实现继承本身并且不使用继承的调用可能更好 .

    我在一年前实现了一个庞大的代码库,为它背后的复杂UML感到自豪,但最近重新审视它是一场噩梦 . 在某些地方,我可以使用更多的自由裁量权来选择使用继承 .

    这个上下文中的问题是:这个继承是否有助于组织代码?它会帮助另一个程序员吗?

    Abstract Classes

    在程序中的任何一点实例化超类的实例,代替其中一个子类是否有意义?如果没有,则抽象超类获得投票 .

  • 2

    如果要使用派生类但将它们作为基类进行掩码,则基类应该具有派生类的所有功能(因为您告诉对象“认为”它是A而忘记它是B) . 所以在我看来,最好的方法是:

    public abstract class A{
       protected abstract void callBar();
       protected abstract void callFooBar();
       protected void callFoo() {
          System.out.pritln("foo");
       }
    }
    
    public class B extends A {
    @Override
      protected void callBar(){
        System.out.println("bar")
      }
    @Override
      protected void callFooBar(){
       callFoo();
       callBar();
      }
    }
    

    然后将B称为A,如下所示:

    A b = new B();
    b.callFooBar();
    

    我认为这是非常可维护的,因为一旦你创建了基类,你就可以灵活地使用派生类做什么,而你的派生类与基类相比,你总是领先一步 . 除非你涉足过度继承,这总是很糟糕 . 总是尝试只有1级继承,偶尔有两次 . 任何其他东西都会迅速失控,如果你需要那么多的继承,那么评估接口是不是更好的选择可能是个好主意 .

相关问题