Qualche lingua OO supporta un meccanismo per garantire che un metodo ignorato chiamerà la base?


12

Penso che questa potrebbe essere una funzione linguistica utile e mi chiedevo se qualche lingua lo supporta già.

L'idea è se hai:

class C
  virtual F
     statement1
     statement2

e

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

Ci sarebbe una parola chiave applicata a CF () in modo tale che la rimozione dell'ultima riga di codice sopra causerebbe un errore del compilatore perché dice "Questo metodo può essere sovrascritto ma l'implementazione qui deve essere eseguita indipendentemente da cosa".


Risposte:


14

Si lo fanno. Si chiama modello scandinavo di OO, è usato ad esempio in Simula (l'altro modello OO che è molto diffuso e considerato come scontato ora, è il modello americano). Nel modello scandinavo, non si sta prevalendo, ma fornendo comportamenti secondari.

nel metodo Superclass foo:

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

nel metodo della sottoclasse foo:

some-code-in-subclass

Se chiami il metodo "istanze" di Superclass solo, some-code-beforee some-code-aftersuccede ( INNERnon fa nulla), ma se chiami foo delle "istanze" della sottoclasse, lo fa some-code-before, some-code-in-subclasse poi some-code-after.


9

Nessuna lingua che conosco impone di chiamare il metodo ignorato. In effetti, alcune lingue consentono metodi di sostituzione che non sono sostituibili (come l'uso della newparola chiave in C #). Tuttavia, ci sono due modi per affrontarlo.

Il primo è quello di creare un metodo irreversibile (ad esempio uno che manca della virtualparola chiave in C # o uno che ha la finalparola chiave in Java) che chiama un metodo sostituibile che non può essere chiamato dall'esterno della classe (ad esempio protectedin C #, Java o C ++).

class C
  A
     statement1
     F
     statement3

  protected virtual F
     statement2

e

class D inherits C

  protected override F
     statement4
     C.F()

Le classi che hanno la precedenza Csono libere di sovrascrivere Fe modificare il suo comportamento, ma i chiamanti esterni alla classe possono accedervi solo attraverso A.

Modifica: come altri hanno sottolineato, questo è chiamato modello del metodo Template .

Il secondo modo è usare un linguaggio che imponga precondizioni e postcondizioni specificate nella classe base, come Eiffel o C # con Contratti di codice. Non forzerà la chiamata della classe base ma il metodo override può essere forzato per eseguire le stesse istruzioni. L'uso degli aspetti può anche aiutare se il linguaggio consente di ereditare gli aspetti.


2
Puoi anche fare in modo che il metodo venga sostituito privatein C ++ :) Herb Sutter lo spiega qui in dettaglio.
Fredoverflow,

Il modello di modello ha solo uno svantaggio di doverlo reimplementare ogni volta mentre si approfondisce la gerarchia dell'ereditarietà. L'esempio con Simula è più elegante e consente ancora il modello di modello.
Pavel Voronin,

7

Non fa davvero parte del linguaggio, ma l'analizzatore di codice statico FindBugs per Java ha un'annotazione OverrideMustInvokeche uno sviluppatore può aggiungere a un metodo e che farà sì che FindBugs mostri un errore se trova un metodo prioritario che non chiama la super implementazione . Permette persino di specificare se la chiamata deve essere la prima o l'ultima nel metodo di sostituzione.


6

La richiesta di chiamare un metodo superclasse è un anti-pattern . Se non viene applicato al momento della compilazione, è soggetto a errori, motivo per cui stai cercando un costrutto linguistico che lo controlli.

Esiste un modo supportato in tutte le lingue OO: il modello di metodo del modello . Qui, rendi il metodo superclasse non sostituibile e in esso chiami un metodo sostituibile. La sottoclasse può quindi sostituire questo metodo per aggiungere funzionalità:

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

A seconda della posizione della chiamata al metodo ignorato, consente persino di determinare l'ordine di esecuzione, che con la normale super chiamata è a volontà dell'implementatore della sottoclasse.


1

Il modello più vicino a cui riesco a pensare sono gli eventi auto-iscritti. È un po 'ingombrante e per nulla intuitivo per il programmatore, ma raggiunge l'obiettivo.

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

    protected event OnF
}

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

    private void F
    {
        ...
    }
}

1
Questo è un modello di progettazione abbastanza comune, a volte con entrambe le sostituzioni pro e post es. ViewWillAppear (), ViewDidAppear (). Ideale quando si desidera consentire alle sottoclassi di estendere (anziché modificare) il comportamento predefinito.
Kris Van Bael,

1

I "sapori" della macchina Lisp consentivano metodi con tipo "before" "after" e "around" il metodo principale ereditato.


0

Sebbene non sia una cattiva idea in teoria, ha l'effetto collaterale negativo di limitare le mie opzioni durante l'implementazione D. Ad esempio, cosa succede se (per qualche motivo insondabile), è più conveniente chiamare l'implementazione della superclasse Fda un altro metodo:

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

In base al tuo scenario, immagino che il compilatore contrassegnerebbe l'implementazione di Fin D, anche se chiama (indirettamente) C.F().

Fondamentalmente, quello che hai descritto è un possibile meccanismo per aiutare il compilatore a riconoscere quando Cviene violato un contratto su classi ereditate . Il mio punto è che, sebbene sia una cosa grandiosa, non dovrebbe andare a scapito di limitare il modo in cui posso implementare la mia sottoclasse.


1
-1: essere in grado di pensare a una situazione in cui non vorresti usare quella che non è una risposta alla domanda "qualsiasi lingua lo consente".

@GrahamLee: molto vero. Il mio punto era cercare di spiegare una delle ragioni per cui nessuna lingua (di cui sono a conoscenza) implementa una simile funzionalità. Immagino di essermi talmente preso dallo spiegarlo, che mi sono dimenticato di menzionare il motivo per cui lo stavo spiegando. -1 felicemente accettato. :)
Mac,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.