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.