简体   繁体   English

在Java中:可以对方法链进行代码重用以调用继承层次结构吗?

[英]In Java: Code reuse possible for a chain of method calls up an inheritance hierarchy?

I have some class inheritance SubClass < MidClass < SuperClass and want to perform some TASK upward for all these classes. 我有一些类继承SubClass <MidClass <SuperClass,并且想为所有这些类向上执行一些任务。 TASK is quite complex with only minor changes in the 3 classes, which I moved into the private methods m2(). TASK非常复杂,仅对3个类进行了微小的更改,我将其移入了私有方法m2()中。

My current solution is very boiler plate: 我当前的解决方案非常实用:

class SuperClass {
  protected void m1() {
    //TASK (calls m2())
  }

  private void m2() {
    //...
  }
}

class MidClass extends SuperClass {
  protected void m1() {
    //same TASK (calls m2())
    super.m1();
  }

  private void m2() {
    //...
  }
}

class SubClass extends MidClass {
  protected void m1() {
    //same TASK (calls m2())
    super.m1();
  }

  private void m2() {
    //...
  }
}

Can I exploit some code reuse mechanism instead of copying TASK? 我可以利用某种代码重用机制来代替复制任务吗?

Something like the following, with m1() only in SuperClass, does not work: 如下所示,仅在SuperClass中带有m1()的东西不起作用:

class SuperClass {
  protected final void m1() {
    //TASK (calls m2())
    if (!(this.getClass().equals(SuperClass.class))) {
      super.m1();
  }
}

because super.m1() does not refer to execution of the same inherited method in the context of a super class, but to the overridden method implementation. 因为super.m1()不在超级类的上下文中引用相同继承方法的执行,而是在重写方法的实现上引用。 Since m1() does not exist in Object, I additionally get a compiler error... 由于对象中不存在m1(),因此我还会收到编译器错误...

Putting TASK in a protected final helper() method in SuperClass and calling helper() instead of copying TASK won't work, since then always SuperClass.m2() gets called. 将TASK放入SuperClass中受保护的final helper()方法中,然后调用helper()而不是复制TASK是行不通的,因为这样始终会调用SuperClass.m2()。

The only alternative I can think of is slow, complicated and unsafe: using a type token as parameter, ie protected final void m1(Class<? extends SuperClass> clazz) in SuperClass, and fulfilling TASK via reflection (requires to make m2() public static or use setAccessible(true) on m2()). 我能想到的唯一选择是缓慢,复杂和不安全:使用类型标记作为参数,即protected final void m1(Class<? extends SuperClass> clazz) ,并通过反射来完成任务(要求使m2()公共静态或在m2()上使用setAccessible(true)。

Do you know some better solution? 您知道更好的解决方案吗? AOP? AOP? Maybe some framework where you can inject a method into classes (as in C#)? 也许是一些框架,您可以在其中将方法注入类(如C#)? Or am I missing something??? 还是我错过了什么?

How about this? 这个怎么样?

class SuperClass {
  protected void m1() {
    //TASK (calls m2())
  }

  protected void m2() {
    //...
  }
}

class MidClass extends SuperClass {

  protected void m2() {
    //...
  }
}

class SubClass extends MidClass {
  protected void m2() {
    //...
  }
}

The m1 method is inherited, and will always call the m2 method. m1方法是继承的,并且将始终调用m2方法。 Since m2 is protected, it's called polymorphically. 由于m2受保护,因此被称为多态。 So, if invoked on a SubClass instance, SubClass.m2() will be called. 因此,如果在SubClass实例上调用,则将调用SubClass.m2()

Expanding on my comment to JB's answer: 扩展我对JB答案的评论:

class SuperClass {
 protected void m1() {
   m2();
 }

 protected void m2() {
   System.out.println("start super task");
   System.out.println("end super task");
 }
}

class MidClass extends SuperClass {
  protected void m2() {
   super.m2();
   System.out.println("start mid task");
   System.out.println("end mid task");
  }
}

class SubClass extends MidClass {
 protected void m2() {
  System.out.println("start sub task");
  super.m2();
  System.out.println("end sub task");
 }
}

new SubClass().m1() yields this result: new SubClass().m1()产生以下结果:

start sub task 开始子任务
start super task 开始超级任务
end super task 结束超级任务
start mid task 开始中期任务
end mid task 中期任务
end sub task 结束子任务

Note that all 3 versions of m2() are executed in the defined order: sub is started, then execution continues with super and mid and finished with sub again. 请注意,所有3个版本的m2()均按定义的顺序执行:sub开始,然后从super和mid继续执行,并再次由sub完成。

Solution for my concrete example of mixed-type equals() with default value constraints instead of ignoring the subclass value fields. 我的带有默认值约束的混合类型equals()的具体示例的解决方案,而不是忽略子类值字段。 Instead of Angelika Langer's solution (see http://www.angelikalanger.com/Articles/JavaSolutions/SecretsOfEquals/Equals-2.html ) with private methods _compareFields() and a protected method _navigateClassHierarchy() that has to be copied into each subclass, only a protected method compareOwnFields() is used, which has to be overridden correctly in each subclass. 而不是使用私有方法_compareFields()和受保护的方法_navigateClassHierarchy()复制到每个子类中的解决方案(请参阅http://www.angelikalanger.com/Articles/JavaSolutions/SecretsOfEquals/Equals-2.html ), ,仅使用受保护的方法compareOwnFields(),该方法必须在每个子类中正确覆盖。

class SuperClass {
    // ...

    @Override
    public final boolean equals(final Object other) {
        if (other == this) { return true; }
        if (!(other instanceof SuperClass)) {
            return false;
        }
        final SuperClass otherSuperClass = (SuperClass) other;

        return compareOwnFields(otherSuperClass, false)  
        && otherSuperClass.compareOwnFields(this, true);
    }

    protected boolean compareOwnFields(final SuperClass other, 
        final boolean firstTraversal) {
        if (!firstTraversal) {
            return true;
        }
        if (field1 != other.getField1()) {
           return false;
        } 
        // compare other fields similarly ...
        return true;
    }

}    

class SubClass {
    // ...

    @Override
    protected boolean compareOwnFields(final SuperClass other, 
        final boolean firstTraversal) {
        if (other instanceof SubClass && !firstTraversal) {
            return true;
        if (other instanceof SubClass) {
            if (field1 != ((SubClass) other).getField1()) {
                return false;
            }
            // compare other fields similarly ...
            return super.compareOwnFields(other, firstTraversal);
        } else {
            if (field1 != DEFAULT_FIELD1) {
                return false;
            }
            // check other fields for default values similarly ..
            return super.compareOwnFields(other, firstTraversal);
        }
    }
}

But this does not answer my question in general, it's rather a redesign that avoids the problem. 但这通常不能回答我的问题,而是可以避免该问题的重新设计。 So further answers on how to solve the problem with the Java language features are very welcome! 因此,欢迎进一步解答如何解决Java语言功能的问题!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM