0

I have some class inheritance SubClass < MidClass < SuperClass and want to perform some TASK upward for all these classes. TASK is quite complex with only minor changes in the 3 classes, which I moved into the private methods 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:

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. Since m1() does not exist in Object, I additionally get a compiler error...

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.

The only alternative I can think of is slow, complicated and unsafe: using a type token as parameter, i.e. 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()).

Do you know some better solution? AOP? Maybe some framework where you can inject a method into classes (as in C#)? Or am I missing something???

4

3 に答える 3

4

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. Since m2 is protected, it's called polymorphically. So, if invoked on a SubClass instance, SubClass.m2() will be called.

于 2011-08-04T10:20:34.560 に答える
0

サブクラス値フィールドを無視する代わりに、デフォルト値制約を使用した混合型equals()の具体的な例の解決策。アンジェリカ・ランガーのソリューション(http://www.angelikalanger.com/Articles/JavaSolutions/SecretsOfEquals/Equals-2.htmlを参照)の代わりに、プライベートメソッド_compareFields()と保護されたメソッド_navigateClassHierarchy()を使用して各サブクラスにコピーする必要があります、保護されたメソッド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);
        }
    }
}

しかし、これは一般的に私の質問に答えるものではなく、問題を回避するための再設計です。したがって、Java言語機能の問題を解決する方法についてのさらなる回答は大歓迎です!

于 2011-08-05T17:53:37.670 に答える
0

Expanding on my comment to JB's answer:

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:

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.

于 2011-08-04T11:22:03.487 に答える