#java #polymorphism #overriding #super #visitor-pattern
#java #полиморфизм #переопределение #супер #посетитель-шаблон
Вопрос:
Обычно переопределенный метод может быть вызван с помощью super. Например:
public class SuperClass {
public void something() {
out("called from super");
}
}
public class SubClass extends SuperClass {
@Override
public void something() {
out("called from sub");
super.something(); // This is fine
}
public static void main(String[] args) {
new SubClass().something(); // Calls both methods
}
}
Но я хочу вызвать метод super.something() из другого класса:
public class SubClass2 extends SuperClass {
@Override
public void something() {
out("called from sub2");
new DecidingClass().maybeCallSuperSomething(this);
}
public static void main(String[] args) {
new SubClass2().something();
}
}
public class DecidingClass {
public void maybeCallSuperSomething(SuperClass visitor) {
boolean keepGoing = true;
// Do some work, maybe set keepGoing to false
// ...
if (keepGoing) {
// How do I call the Overridden method?
visitor.something() // Causes recursive loop
// visitor.super.something() ????
}
}
}
Возможно ли это? У меня есть обходной путь, но он немного неаккуратный.
Ответ №1:
Короткий ответ, нет.
Реализация суперкласса видна только прямым подклассам. Внешние классы в любом случае не должны знать о функциональности отдельных реализаций метода; сцепление = плохое.
Вероятно, вам нужно пересмотреть свой дизайн, если это необходимо.
Комментарии:
1. 1 Эта идея отражена в LSP: en.wikipedia.org/wiki/Liskov_substitution_principle
2. Жаль, я подумал, что это может привести к быстрому решению, следует ли вызывать метод или нет. Обходной путь достаточно прост, для этого просто требуется вызвать суперметод внутри подметода, т.Е. if (new DecidingClass().decide(this)) { super.something(); }
Ответ №2:
Вы не можете вызвать метод super — это часть спецификации Java, но вот (уродливый) вариант:
public class SuperClass {
public void something(boolean invokeSuper) {
// do something
}
}
public class SubClass extends SuperClass {
public void something(boolean invokeSuper) {
if (invokeSuper) {
super.something();
} else {
// do something
}
}
}
Ответ №3:
Это немного очевидно, но… обычный способ справиться с этим — извлечь тело метода базового класса в отдельный метод, чтобы его можно было вызвать напрямую. Возможно, вы захотите, чтобы он был окончательным, как для повышения производительности, так и для того, чтобы подчеркнуть, что его нельзя переопределять.
public class SuperClass {
public void something() {
doSomething();
}
public final void doSomething() {
out("called from super");
}
}
public class DecidingClass {
public void maybeCallSuperSomething(SuperClass visitor) {
// ...
visitor.doSomething();
// ...
}
}