Unterstützen OO-Sprachen einen Mechanismus, um zu gewährleisten, dass eine überschriebene Methode die Basis aufruft?

12

Ich denke, dies könnte eine nützliche Sprachfunktion sein und habe mich gefragt, ob es bereits Sprachen gibt, die dies unterstützen.

Die Idee ist, wenn Sie haben:

class C
  virtual F
     statement1
     statement2

und

class D inherits C
  override F
     statement1
     statement2
     C.F()

Auf CF () würde ein Schlüsselwort angewendet, so dass das Entfernen der letzten Codezeile zu einem Compilerfehler führen würde, da die Meldung "Diese Methode kann überschrieben werden, die Implementierung hier muss jedoch ausgeführt werden, egal was passiert" lautet.

Aaron Anodide
quelle

Antworten:

14

Ja, das tun sie. Es heißt skandinavisches Modell von OO, es wird zum Beispiel in Simula verwendet (das andere OO-Modell, das weit verbreitet ist und jetzt als selbstverständlich angenommen wird, ist ein amerikanisches Modell). Im skandinavischen Modell überschreiben Sie nicht, sondern liefern Unterverhalten.

in Superklasse Methode foo:

some-code-before
INNER // this is the actual Simula keyword
some-code-after

in Unterklasse 'Methode foo:

some-code-in-subclass

Wenn Sie übergeordnete Klasse nennen foo Instanzen Methode, nur some-code-beforeund some-code-aftergeschieht ( INNERtut nichts), aber wenn man Subclass nennen foo Instanzen, tut es some-code-before, some-code-in-subclassund dann some-code-after.

herby
quelle
9

Keine mir bekannte Sprache erzwingt das Aufrufen der überschriebenen Methode. In der Tat erlauben einige Sprachen das Überschreiben von Methoden, die nicht überschrieben werden können (z. B. die Verwendung des newSchlüsselworts in C #). Es gibt jedoch zwei Möglichkeiten, dies zu erreichen.

Die erste Möglichkeit besteht darin, eine nicht überschreibbare Methode zu erstellen (z. B. eine, bei der das virtualSchlüsselwort in C # fehlt oder die das finalSchlüsselwort in Java enthält), die eine überschreibbare Methode aufruft, die nicht von außerhalb der Klasse aufgerufen werden kann (z. B. protectedin C #, Java oder C ++).

class C
  A
     statement1
     F
     statement3

  protected virtual F
     statement2

und

class D inherits C

  protected override F
     statement4
     C.F()

Das Überschreiben von Klassen steht Ces frei, das FVerhalten zu überschreiben und zu ändern, aber Anrufer von außerhalb der Klasse greifen nur über zu A.

Bearbeiten: Wie bereits erwähnt, wird dies als Template-Methodenmuster bezeichnet .

Die zweite Möglichkeit besteht darin, eine Sprache zu verwenden, die in der Basisklasse angegebene Vor- und Nachbedingungen wie Eiffel oder C # mit Codeverträgen erzwingt. Der Aufruf der Basisklasse wird nicht erzwungen, aber die überschriebene Methode kann gezwungen werden, dieselben Anweisungen auszuführen. Die Verwendung von Aspekten kann auch hilfreich sein, wenn die Sprache die Vererbung von Aspekten ermöglicht.

akton
quelle
2
Sie können sogar festlegen, dass die Methode privatein C ++ überschrieben wird :) Herb Sutter erklärt dies hier ausführlich.
Fredoverflow
Das Vorlagenmuster hat nur den Nachteil, dass Sie es jedes Mal neu implementieren müssen, während Sie die Vererbungshierarchie vertiefen. Das Beispiel mit Simula ist eleganter und erlaubt immer noch Vorlagenmuster.
Pavel Voronin
7

Nicht wirklich Teil der Sprache, aber der FindBugs Static Code Analyzer für Java verfügt über eine Anmerkung OverrideMustInvoke, die ein Entwickler zu einer Methode hinzufügen kann und die dazu führt, dass FindBugs einen Fehler anzeigt, wenn eine überschreibende Methode gefunden wird, die die Super-Implementierung nicht aufruft . Es kann sogar angegeben werden, ob der Aufruf in der überschreibenden Methode der erste oder der letzte sein muss.

Michael Borgwardt
quelle
6

Das Aufrufen einer Superklasse-Methode ist ein Anti-Pattern . Wenn es zur Kompilierungszeit nicht erzwungen wird, ist es fehleranfällig. Aus diesem Grund suchen Sie nach einem Sprachkonstrukt, das es überprüft.

Es gibt einen Weg, der in allen OO-Sprachen unterstützt wird: Das Template-Methodenmuster . Hier machen Sie die Superklasse-Methode nicht überschreibbar und rufen darin eine überschreibbare Methode auf. Die Unterklasse kann dann diese Methode überschreiben, um Funktionen hinzuzufügen:

class super {
  public final void doSomething() {
    doSpecialthing();
    doMore();
  }
  public void doSpecialthing() {
  }
}

Abhängig vom Ort des Aufrufs der überschriebenen Methode kann sogar die Ausführungsreihenfolge bestimmt werden, die beim normalen Super-Aufruf vom Implementierer der Unterklasse frei gewählt wird.

Ozan
quelle
1

Das nächste Muster, das ich mir vorstellen kann, sind selbst abonnierte Ereignisse. Es ist etwas umständlich und für den Programmierer überhaupt nicht intuitiv, erreicht aber das Ziel.

class C
{
    public void F()
    {
        ...
        OnF()
    }

    protected event OnF
}

class D : C
{
    public D()
    {
        base.OnF += this.F
    }

    private void F
    {
        ...
    }
}
Hand-E-Food
quelle
1
Dies ist ein häufig vorkommendes Entwurfsmuster, manchmal mit Pro-Overrides und Post-Overrides, z. ViewWillAppear (), ViewDidAppear (). Ideal, wenn Sie Unterklassen erlauben möchten, das Standardverhalten zu erweitern (statt zu ändern).
Kris Van Bael
1

Lisp-Maschine "schmeckt" erlaubte Methoden mit dem Typ "vor" "nach" und "um" die geerbte Hauptmethode.

ddyer
quelle
0

Theoretisch ist dies zwar keine schlechte Idee, hat aber den negativen Nebeneffekt, dass meine Optionen bei der Implementierung eingeschränkt werden D. Was ist zum Beispiel, wenn es (aus unerfindlichen Gründen) bequemer ist, die Superklasse-Implementierung Fvon einer anderen Methode aufzurufen :

class D inherits C
    override F
        statement1
        statement2
        G()
    G
        statement3
        C.F()
        statement4

In Ihrem Szenario würde der Compiler die Implementierung von Fin Dkennzeichnen, obwohl er (indirekt) aufruft C.F().

Grundsätzlich ist das, was Sie beschrieben haben, ein möglicher Mechanismus, mit dem der Compiler erkennen kann, wenn ein Vertrag über Klassen, von denen erbt, Cverletzt wird. Mein Punkt ist, dass, obwohl das eine großartige Sache ist, es nicht auf Kosten der Einschränkung gehen sollte, wie ich meine Unterklasse implementieren kann.

Mac
quelle
1
-1: In der Lage zu sein, sich eine Situation vorzustellen, in der man das nicht nutzen möchte, ist keine Antwort auf die Frage "Erlaubt das eine Sprache?".
@ AbrahamLee: sehr wahr. Ich wollte versuchen, einen Grund zu erklären, warum keine Sprache (die mir bekannt ist) eine solche Funktion implementiert. Ich glaube, ich war so sehr damit beschäftigt, das zu erklären, dass ich vergaß zu erwähnen, warum ich es erklärte. -1 gerne angenommen. :)
Mac