如何强制我的类的任何子类始终调用它们重写的父实现方法?

DVK*_*DVK 6 java oop inheritance overriding design-patterns

假设我有一个类,它实现了一个方法(addThings()).它作为子类树的基础:

ParentClass {
    protected void addThings() {
        map.add(thing1);
        map.add(thing2);
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,假设我们实现了一个子类(也有Thing 3),而Thing 3也需要添加在Thing 1和Thing 2之上.

显而易见的Java解决方案似乎是让子类的方法实现调用super的方法:

ChildClass extends ParentClass {
    protected void addThings() {
        super.addThings();
        map.add(thing3);
    }
}
Run Code Online (Sandbox Code Playgroud)

问题是,实现子类的人可能会忘记这样做,并且有一个错误:

ChildClassBad extends ParentClass {
    protected void addThings() {
        // BUG!!! Forgot to call super.addThings(); !!!
        map.add(thing3); 
    }
}
Run Code Online (Sandbox Code Playgroud)

在Java中是否有一种方法可以强制任何扩展子(和孙子)类在它们覆盖它时总是调用父方法?(类似于如何使方法抽象总是迫使它们实现它).

  • 请注意,我需要在继承树下传播解决方案.

    换句话说,如果某人实现需要添加Thing4的GrandChildClass,他们将遭受与ChildClass相同的bug可能性.

    这意味着在ParentClass中具有单独的"addParentThings()"然后同时调用addParentThings()和child-overridable empty addThings()的简单修复(适用于只有1级继承时)是不够的(因为孙子必须覆盖非空的addThings).

Anu*_*oob 5

也许尝试使用调用另一个可覆盖方法的最终方法?

class ParentClass {

    public final void doStuff() {
        // Do stuff
        onPostDoStuff();
    }

    protected void onPostDoStuff() {
        // Override this!
    }
}
Run Code Online (Sandbox Code Playgroud)

然后在子类中:

class ChildClass extends ParentClass {

    @Override
    protected void onPostDoStuff() {
        // Do extra stuff
    }
}
Run Code Online (Sandbox Code Playgroud)

你甚至可以使onPostDoStuff()方法变得抽象,所以孩子们必须覆盖它.

  • 这似乎**并非全部**帮助孙子类重写子类的方法?(你似乎只是采取了我在帖子的后半部分明确拒绝的解决方案,并在其上打了一个"最终",尽管没有任何帮助) (3认同)

Tur*_*g85 2

如果您愿意doStuff为每个类使您的 -Methods 静态,从而扩展您的方法ParentClass并为您提供ParentClass-Method final public void doAllStuff(),您可以使用反射解决问题:

import java.lang.reflect.Method;

import java.util.ArrayList;
import java.util.List;

public class Main
{
    public static void main(String[] args) throws InterruptedException
    {
        A a = new C();
        a.doAllStuff();
    }
}

class A
{
    protected List<String> list = new ArrayList<String>();

    @SuppressWarnings("unused")
    private static void doStuff(A a)
    {
        a.list.add("I am A");
    }

    final public void doAllStuff()
    {
        List<Class<?>> list = new ArrayList<Class<?>>();
        Class<?> clazz = this.getClass();
        while (A.class.getSuperclass() != clazz)
        {
            list.add(clazz);
            clazz = clazz.getSuperclass();
        }
        System.out.println(list);
        for (Class<?> myClass : list)
        {
            try
            {
                Method method = myClass.getDeclaredMethod("doStuff"
                                                          , myClass);
                // Method is private? Make it accessible anyway.
                method.setAccessible(true);
                method.invoke(this, this);
            }
            catch (NoSuchMethodException e)
            {
                // Method not found, continue with next class.
                continue;
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
        }
        System.out.println(this.list);
    }
}

class B extends A
{
    @SuppressWarnings("unused")
    private static void doStuff(B b)
    {
        b.list.add("I am B");
    }
}

class C extends B {}
Run Code Online (Sandbox Code Playgroud)

如果你只需要调用属性,你可以使用getDeclaredField,字段可能不是static这种情况。