Algum idioma OO suporta um mecanismo para garantir que um método substituído chamará a base?

12

Eu acho que esse pode ser um recurso útil da linguagem e fiquei pensando se algum idioma já o suporta.

A ideia é se você tiver:

class C
  virtual F
     statement1
     statement2

e

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

Haveria uma palavra-chave aplicada ao CF (), que remover a última linha de código acima causaria um erro do compilador, porque está dizendo "Esse método pode ser substituído, mas a implementação aqui precisa ser executada, não importa o que aconteça".

Anodeto de Aaron
fonte

Respostas:

14

Sim, eles fazem. É chamado modelo escandinavo de OO, é usado, por exemplo, em Simula (o outro modelo de OO que é amplamente difundido e considerado como garantido agora, é o modelo americano). No modelo escandinavo, você não está substituindo, mas fornecendo sub-comportamento.

no método da Superclasse foo:

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

no método da subclasse foo:

some-code-in-subclass

Se você chamar o método foo casos superclasse, única some-code-beforee some-code-afteracontece ( INNERnão faz nada), mas se você chamar foo casos subclasse, ele faz some-code-before, some-code-in-subclasse depois some-code-after.

Herby
fonte
9

Nenhum idioma que eu conheço impõe a chamada do método substituído. De fato, algumas linguagens permitem substituir métodos que não são substituíveis (como usar a newpalavra - chave em C #). No entanto, existem duas maneiras de abordar isso.

O primeiro é criar um método irrecuperável (por exemplo, um que não tenha a virtualpalavra - chave em C # ou um que tenha a finalpalavra - chave em Java) que chame um método substituível que não possa ser chamado de fora da classe (por exemplo, protectedem C #, Java ou C ++).

class C
  A
     statement1
     F
     statement3

  protected virtual F
     statement2

e

class D inherits C

  protected override F
     statement4
     C.F()

A substituição de classes Cé livre para substituir Fe modificar seu comportamento, mas os chamadores de fora da classe apenas acessam-na A.

Edit: Como outros já apontaram, isso é chamado de padrão do método Template .

A segunda maneira é usar uma linguagem que imponha pré-condições e pós-condições especificadas na classe base, como Eiffel ou C # com Code Contracts. Não forçará a chamada da classe base, mas o método substituído poderá ser forçado a executar as mesmas instruções. O uso de aspectos também pode ajudar se o idioma permitir que aspectos sejam herdados.

Akton
fonte
2
Você pode até tornar o método anulado privateem C ++ :) Herb Sutter explica aqui em detalhes.
Fredoverflow 26/09/12
O padrão de modelo tem apenas uma desvantagem que você precisa reimplementá-lo a cada vez, aprofundando a hierarquia de herança. O exemplo com o Simula é mais elegante e ainda permite o padrão de modelo.
Pavel Voronin
7

Não é realmente parte da linguagem, mas o analisador de código estático do FindBugs para Java possui uma anotação OverrideMustInvokeque um desenvolvedor pode adicionar a um método e que fará com que o FindBugs mostre um erro se encontrar um método de substituição que não chame a super implementação . Ele ainda permite especificar se a chamada deve ser a primeira ou a última no método de substituição.

Michael Borgwardt
fonte
6

Exigir chamar um método de superclasse é um anti-padrão . Se não for aplicado em tempo de compilação, é propenso a erros, e é por isso que você está procurando por uma construção de linguagem que a verifique.

Existe uma maneira que é suportada em todos os idiomas OO: O padrão do método de modelo . Aqui, você torna o método da superclasse não substituível e nele chama um método substituível. A subclasse pode substituir esse método para adicionar funcionalidade:

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

Dependendo da localização da chamada para o método substituído, ele ainda permite determinar a ordem de execução, que com a super chamada comum fica à vontade do implementador da subclasse.

Ozan
fonte
1

O padrão mais próximo que consigo pensar é em eventos autoassinados. É um pouco complicado, e nada intuitivo para o codificador, mas atinge o objetivo.

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

    protected event OnF
}

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

    private void F
    {
        ...
    }
}
Mão-E-Comida
fonte
1
Esse é um padrão de design bastante comum, às vezes com substituições profissionais e posteriores, por exemplo. ViewWillAppear (), ViewDidAppear (). Ideal quando você deseja permitir que as subclasses estendam (em vez de modificar) o comportamento padrão.
Kris Van Bael
1

A máquina Lisp "sabores" permitia métodos com o tipo "before" "after" e "around" o método principal herdado.

ddyer
fonte
0

Embora não seja uma má idéia em teoria, ela tem o efeito colateral negativo de restringir minhas opções ao implementar D. Por exemplo, e se (por algum motivo insondável), for mais conveniente chamar a implementação da superclasse de Falgum outro método:

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

No seu cenário, imagino que o compilador sinalize a implementação de Fin D, mesmo que chame (indiretamente) C.F().

Basicamente, o que você descreveu é um mecanismo possível para ajudar o compilador a reconhecer quando um contrato de classes herdadas Cé violado. O que quero dizer é que, embora isso seja ótimo, não deve prejudicar a limitação de como posso implementar minha subclasse.

Mac
fonte
1
-1: ser capaz de pensar em uma situação em que você não gostaria de usar que não é uma resposta para a pergunta "algum idioma permite isso".
@ GrahamLee: muito verdade. Meu objetivo era tentar explicar uma razão pela qual nenhuma linguagem (que eu saiba) implementa esse recurso. Acho que fiquei tão envolvido em explicar isso, que esqueci de mencionar por que estava explicando isso. -1 aceito com satisfação. :)
Mac