В Java: возможно ли повторное использование кода для цепочки методов, вызывающих иерархию наследования? - PullRequest
0 голосов
/ 04 августа 2011

У меня есть некоторый класс наследования SubClass

Мое текущее решение очень простое:

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() {
    //...
  }
}

Могу ли я использовать какой-то механизм повторного использования кода вместо копирования ЗАДАЧИ?

Что-то вроде следующего, с m1 () только в SuperClass, не работает:

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

, потому что super.m1 () не ссылается на выполнение того же унаследованного метода вконтекст суперкласса, но для реализации переопределенного метода.Так как m1 () не существует в Object, я дополнительно получаю ошибку компилятора ...

Помещение TASK в защищенный метод final helper () в SuperClass и вызов helper () вместо копирования TASK не будут работать, с тех пор всегда вызывается SuperClass.m2 ().

Единственная альтернатива, о которой я могу думать, это медленная, сложная и небезопасная: использование токена типа в качестве параметра, например protected final void m1(Class<? extends SuperClass> clazz) в SuperClass, и выполнение TASK черезотражением (требует сделать m2 () общедоступным статическим или использовать setAccessible (true) для m2 ()).

Знаете ли вы лучшее решение?АОП?Может быть, какая-то структура, где вы можете внедрить метод в классы (как в C #)?Или я что-то упустил ???

Ответы [ 3 ]

4 голосов
/ 04 августа 2011

Как насчет этого?

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() {
    //...
  }
}

Метод m1 наследуется и всегда будет вызывать метод m2.Поскольку m2 защищен, он называется полиморфным.Таким образом, если вызывается для экземпляра SubClass, будет вызываться SubClass.m2().

0 голосов
/ 05 августа 2011

Решение для моего конкретного примера 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, очень приветствуются!

0 голосов
/ 04 августа 2011

Расширение моего комментария к ответу 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() дает такой результат:

запуск подзадачи
запуск суперзадачи
конец суперзадачизадача
запуск в середине задачи
конец в середине задачи
завершение подзадачи

Обратите внимание, что все 3 версии m2() выполняются в определенном порядке: запускается подпрограмма, затем выполнение продолжается с super и mid и заканчивается с sub снова.

...