15.5. Herança de contratos versus redefinição

Os dois exemplos que vimos na secção anterior ilustram situações extremamente comuns em programação – a necessidade de generalizar ações semelhantes, identificando as partes comuns e as que variam:

 

Como o tipo declarado dos objetos é Jogo, ainda que o seu tipo concreto possa ser qualquer subtipo de Jogo,

 

Exemplo de pré-condições

Ainda usando o exemplo do método vencedores, relembremos a linha de comentário que define a sua pré-condição na classe Jogo:

Na redefinição deste método na classe JogoComObjetivo, a pré-condição não poderá ser mais restritiva (mais forte). Deverá ser igual ou menos restritiva (mais fraca):

 

Exemplo de pós-condições

Vamos agora ver o exemplo do método void registarPontosJogada(String nome, int pontos). Embora não tenhamos apresentado pós-condição para este método na classe Jogo, ela poderia ser:

Na redefinição deste método na classe JogNumeroExatoJogadas, a pós-condição deverá garantir esta condição ou outra mais forte:

 

 

No geral,

para duas classes A e B, em que B é subclasse de A, temos que, para todo o método m acessível aos clientes de A:

Ou seja, B não pode exigir mais nem prometer menos!

 

Isto leva-nos ao princípio conhecido por Liskov substitution principle:

Só fazendo com que a subclasse honre os contratos da superclasse conseguimos garantir que:

 

 


 

Anterior: 15.4. Invocação indireta de métodos redefinidos

Seguinte: 15.6. Tipos genéricos e sub-tipos