Как убедиться, что в дочернем элементе вызывается суперметод?

Если у меня есть метод public void send() { /* some code */ } в классе и у дочернего элемента этого класса также есть метод public void send() { /* some code*/ }, как я могу гарантировать, что дочерний элемент должен вызывать super.send() где-то в методе send(), который он пытается переопределить?

Мне было интересно об этом, потому что я написал в API, где, если вы не вызовете супер метод при его переопределении, он выдаст исключение, сообщающее мне, что я не вызывал суперметод. Это жестко закодировано или это можно сделать с помощью некоторых ключевых слов в Java?


person Brian    schedule 23.05.2011    source источник


Ответы (7)


Ты действительно не можешь, но ты можешь...

class MySuperClass {
    public final void send() {
        preSend();
        // do the work...
        postSend();
    }

    protected void preSend() {
        // to be overridden in by sub classes
    }

    protected void postSend() {
        // to be overridden in by sub classes
    }

}
person Tom    schedule 23.05.2011
comment
Это, вероятно, лучше для большинства вещей. Однако вы можете использовать флаги для принудительного вызова во время выполнения (но нет перехвата во время компиляции). - person Ted Hopp; 23.05.2011
comment
Я бы сделал preSend() и postSend() виртуальными. Это потому, что они могут не вызываться, если объект создан как: MySuperClass * obj = new ClassDerivedFromMySuperClass(); Это очень часто используемый подход (например, для плагинов) и делает ClassDerivedFromMySuperClass::preSend() и ClassDerivedFromMySuperClass::postSend() не вызываемыми. - person Predrag Manojlovic; 25.06.2014
comment
Вопрос и ответ о java - person Tom; 25.06.2014
comment
@ Том, конечно, но если бы этот вопрос был задан о C # или C ++, он, вероятно, был бы помечен как дубликат и перенаправлен сюда. Нет ничего плохого в некоторой дополнительной информации, которая может иметь отношение к тем, кто наткнется сюда из Google. - person Miguel Bartelsman; 27.05.2021

Вы можете сделать это, добавив абстрактный метод (не вижу другого пути):

abstract class MyClass 
{

public final void send()  // forbid changing this.
{
 // do something
 doSend():
}

protected abstract doSend(); // no external calls

}
person ic3    schedule 23.05.2011

http://en.wikipedia.org/wiki/Call_super

То, что вы пытаетесь сделать, является анти-шаблоном; вы можете сделать это (многие базовые классы Java делают это), но вы не должны - если у вас нет для этого действительно веской причины.

За исключением этого бита, все ответы, представленные здесь, верны.

person Community    schedule 21.05.2012
comment
Это то, что я искал. Я чувствовал, что что-то не так с обязательством пользователей звонить родителю, но не знал причины и решения. - person farzan; 19.01.2015

Концептуально это похоже на «делегирование полномочий ребенку». Для этого родительский класс должен реализовать метод final, который вызывает абстрактный метод, который должен реализовать дочерний класс.

abstract class Parent {

    public final void invoke() {
        // pre invoke code
        doInvoke():
        // post invoke code
    }

    protected abstract doInvoke(); // child should implement this
}
person Ramesh PVK    schedule 23.05.2011

Вы не можете заставить подкласс вызывать базовый. Одна вещь, которую вы можете сделать, это изменить метод отправки на базовый (окончательный) «отправить» и «отправить ядро» (виртуальный), которые будут переопределены подклассами. Базовый «send» установит некоторый флаг, указывающий, что «sendcore» не был вызван, а затем вызовет «sendcore». Когда он возвращается, он может проверить, вызвал ли дочерний «sendcore» базовый класс.

person carlosfigueira    schedule 23.05.2011

Нет ключевого слова, которое обеспечивает это. По-моему, вы либо

  1. Предоставьте подклассу всю информацию (через защищенные методы или что-то еще), необходимую для полного переопределения и изменения самого вызова send, или...
  2. Задокументируйте API, чтобы было известно, что в конечном итоге они должны сами вызывать send через super. Я полагаю, что большинство людей, которые переопределяют метод суперкласса, сделали бы это, если бы в любом случае была абстрагирована достаточная часть класса.
person Ben J    schedule 23.05.2011

В Java нет ничего встроенного для принудительного вызова метода суперкласса. Один из подходов к этому — использовать частные флаги в суперклассе вместе с методом делегирования. Что-то вроде этого:

public class Super {
    private boolean inSend;
    private boolean superCalled;
    public final void send() {
        inSend = true;
        superCalled = false;
        doSend();
        inSend = false;
        if (!superCalled) {
            throw new IllegalStateException("Failed to call super.doSend()");
        }
    }
    protected void doSend() {
        if (!inSend) {
            throw new IllegalStateException("Cannot call doSend() directly");
        }
        superCalled = true;
        // base class functionality
    }
}
person Ted Hopp    schedule 23.05.2011