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).
也许尝试使用调用另一个可覆盖方法的最终方法?
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()
方法变得抽象,所以孩子们必须覆盖它.
如果您愿意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
这种情况。