Ir para o conteúdo

Heranças de classes

Introdução

Exactamente com o mesmo sentido que o vulgarmente conhecido, uma herança é algo que é deixado a alguém e o conceito de herança no Visual Basic 2008 passa exactamente por aí. Quando tentamos construír estructuras e relações hierárquicas entre classes, ou até mesmo quando descobrimos que determinado tipo de características ou métodos são comuns a vários elementos, procuramos descobrir maneiras das classes herdarem da sua base.

Em que situações?

Se a pergunta continua a ser: "em que situações terei alguma vez de empregar heranças?", vamos examinar o seguinte exemplo:

Um programador informático e um jogador de golfe são pessoas. Uma pessoa partilha com todas as outras alguns dados. Nome, idade, morada, naturalidade e nacionalidade, por exemplo, são características comuns a qualquer pessoa quer ela seja programadora de informática ou jogadora de golfe. Vamos agarrar nestes dois tipos de pessoas e vamos escrever uma classe que as defina.

Aviso: Os seguintes blocos de código não se encontram de acordo com as regras de encapsulamento de classes (noções não incluídas neste artigo). São escritos com o intuito de explicar heranças entre classes. As regras de encapsulamento devem ser aplicadas sempre que possível.

Public Class ProgramadorTI
    Public Nome
    Public Idade
    Public Morada
    Public Naturalidade
    Public Nacionalidade
    Public HorasDeComputador
    Public CocaColasConsumidasAProgramar
    Public NumeroDeLinguagensQueDomina
End Class

Public Class JogadorGolfe
    Public Nome
    Public Idade
    Public Morada
    Public Naturalidade
    Public Nacionalidade
    Public MediaTacadasPorJogo
    Public SalarioPagoAoCaddie
    Public QuilometrosFeitosDeCarrinho
End Class

Como já foi referido, existem 5 características que são perfeitamente comuns entre estas duas classes e é nestes casos em que devem entrar as heranças. É certo que não parece fazer grande diferença, mas se descobrirmos 100 características comuns numa pessoa, seriam as mesmas 100 características que ser repetidas tantas vezes quantas novas profissões quisessemos acrescentar. Eis o aspecto das classes depois de implementar as heranças:

Public Class ProgramadorTI
    Inherits Pessoa
    Public HorasDeComputador
    Public CocaColasConsumidasAProgramar
    Public NumeroDeLinguagensQueDomina
End Class

Public Class JogadorGolfe
    Inherits Pessoa
    Public MediaTacadasPorJogo
    Public SalarioPagoAoCaddie
    Public QuilometrosFeitosDeCarrinho
End Class

Public Class Pessoa
    Public Nome
    Public Idade
    Public Morada
    Public Naturalidade
    Public Nacionalidade
End Class

A partir de agora, sempre que quisermos adicionar um novo programador, as características comuns embutidas na classe Pessoa passam a fazer parte da nova classe ProgramadorTI sem que as tenhamos de repetir. Exactamente o mesmo se vai passar com novas instâncias da classe JogadorGolfe. A indicação de que queremos herdar uma classe reside na constatação Inherits que significa literalmente "herda", seguida do nome da classe a herdar.

Estas características podem traduzir-se em propriedades, até métodos. Vamos supor que era importante existir um método que, de acordo com a idade da pessoa, nos devolvesse o ano em que nasceu. Como à partida é um cálculo que pode ser efectuado em todas as pessoas, um método como este é possível passar em forma de herança para as suas classes derivadas.

Public Class Pessoa
    Public Nome
    Public Idade
    Public Morada
    Public Naturalidade
    Public Nacionalidade

    Public Function AnoEmQueNasceu()
        Dim AnoActual = Now.Year
        Return AnoActual - Idade
    End Function
End Class

Agora, a partir de qualquer classe que desta derive, é possível determinar o ano em que nasceu, partindo do método que reside na classe base.

        Dim p As New JogadorGolfe
        p.Idade = 9
        MsgBox(p.AnoEmQueNasceu)

Excepções à regra

Porque existem excepções às regras, se determinarmos que um método é na maior parte das vezes comum, mas por vezes pode não ser, teremos de preparar esse método da classe a herdar de forma a que possa ignorar o método base e aplique o método particular da nova instância. Tomemos, por exemplo, um mentiroso. Imaginemos que alguém determinou que a idade de um mentiroso deverá oscilar desde a idade que ele diz ter até menos 4 anos. No nosso método base já temos um problema, pois o cálculo da idade é feito com base na idade que a instância tem, e nós não queremos informações faliciosas. A solução são overrides, ou "tomadas de controlo". Teremos de acrescentar o método que se deve utilizar para este tipo de pessoa em particular e um pequeno pormenor no método base, indicando que este pode ser "invalidado":

Public Class Pessoa
    Public Nome
    Public Idade
    Public Morada
    Public Naturalidade
    Public Nacionalidade

    Public Overridable Function AnoEmQueNasceu()
        Dim AnoActual = Now.Year
        Return AnoActual - Idade
    End Function
End Class

Public Class Mentiroso
    Inherits Pessoa
    Public MentirasContadas
    Public NumeroDeFraudes
    Public ReformasDesviadas

    Public Overrides Function AnoEmQueNasceu()
        Dim AnoActual = Now.Year
        Randomize()
        Return AnoActual - (Idade - (CInt(Rnd() * 4)))
    End Function
End Class

Agora, a classe Mentiroso vai deixar de utilizar o método base comum e vai passar a utilizar o seu próprio método.

Ideia: As tomadas de controlo são válidas também para propriedades (Properties).

Proteger as origens

Imaginemos que, por alguma razão, não desejamos que a classe Pessoa possa ser instanciada. Queremos apenas que esta classe sirva como base para as instâncias de outras classes que desta derivem. Basta declarar a classe que pretendemos que seja para herdar apenas com MustInherit:

Public MustInherit Class Pessoa
    Public Nome
    Public Idade
    Public Morada
    Public Naturalidade
    Public Nacionalidade

    Public Overridable Function AnoEmQueNasceu()
        Dim AnoActual = Now.Year
        Return AnoActual - Idade
    End Function
End Class

Se tentarmos instanciar a classe Pessoa, vamos verificar que é impossível. Se, por outro lado, for necessária a instanciação da classe base, mas existam algumas propriedades ou métodos que não possam estar acessíveis em novas instâncias sem ser através de classes derivadas, deveremos usar a constatação "Protected" ou protegido. Vamos proteger, por exemplo, a naturalidade e nacionalidade das novas instâncias directas:

Public Class Pessoa
    Public Nome
    Public Idade
    Public Morada
    Protected Naturalidade
    Protected Nacionalidade

    Public Overridable Function AnoEmQueNasceu()
        Dim AnoActual = Now.Year
        Return AnoActual - Idade
    End Function
End Class

Se instanciarmos a classe Pessoa verificaremos que esta nova instância não possuí nem nacionalidade, nem naturalidade. No entanto, em qualquer uma das suas classes derivadas, naturalidade e nacionalidade fazem parte da classe.

Ideia: É possível proteger métodos e propriedades.

Conclusão

O conceito de herança é extremamente poderoso no que toca à reutilização e organização de código. O seu correcto uso poderá poupar horas de trabalho a quem escreve o código a primeira vez e depois a quem o vai manter ao longo dos anos. Não é demais lembrar que os blocos de código expostos no artigo não estão de acordo com as regras básicas de encapsulamento e servem única e exclusivamente para dar a entender de uma maneira mais fácil a utilização de heranças.