Uma das principais atividades e, também uma boa prática na programação usando o R é a utilização da abordagem de
programação orientada a objetos. Essa proposta é útil na construção de pacotes no R bem como na organização e estabilidade das bibliotecas criadas. Nesse tutorial iremos trabalhar com a
classe S4 de objetos do R.
Suponha que desejamos criar um pacote que nos ajude a calcular a menção de alunos de uma turma. Nesse caso, o sistema de
classes S4 pode ser definido criando-se o objeto aluno:
1 2 3 4 5 | setClass (
"Aluno" ,
representation (nome= "character" , idade= "numeric" ),
prototype (nome= character (0), idade= numeric (0))
)
|
Esse objeto contêm, inicialmente, dois
slots: a idade do aluno e seu nome. O nome é considerado nesse modelo uma variável
caracter e a idade uma variável
numérica. O comando
prototype define quais devem ser os valores iniciais para esses dois atributos.
Entretanto, na universidade nós temos diversos tipos de aluno, eles podem ser: alunos da graduação, pós-graduação, extensão, aluno especial, ouvinte, etc. Suponha que tenhamos dois tipos de alunos apenas:
1 2 3 4 5 6 7 8 | setClass ( "Graduacao" ,
representation (nota1= "numeric" ,nota2= "numeric" ,nota3= "numeric" ),
contains= "Aluno" )
setClass ( "Posgraduacao" ,
representation (artigo= "character" ,nota1= "numeric" ,nota2= "numeric" ),
contains= "Aluno" )
|
Na primeira subclasse donominada
Graduação o aluno faz três provas representadas pelos
slots:
nota1,
nota2 e
nota3. Já na segunda subclasse o aluno é um aluno de
Pós-graduação e ele é avaliado de maneira diferente, tem que preparar um artigo o qual pode ser armazenado no
slot artigo e faz duas provas cujas notas são armazenadas em
nota1 e
nota 2. Note que nesse caso, ambos são
Alunos e por isso herdam os atributos de
nome e
idade.
Além do mais, na criação dessas subclasses não atribuímos os valores iniciais desses atributos por opção.
A boa prática, no entanto, recomenda que todos esses atributos sejam definidos os valores de inicialização através do método
prototype.
Cada tipo de aluno terá sua nota calculada de maneira diferente: para os alunos de graduação a nota final será a média das três notas nas provas, já os alunos de Pós-graduação a nota será 50% da média das duas provas e 50% se ele fez o artigo e zero se não fez. Nesse caso, usaremos a propriedade de
Mutabilidade (Mutability) dos sistemas de programação orientada a objetos. Através dessa propriedade um cômputo diferente será realizado para cada tipo de objeto. O primeiro passo é a criação de um método genérico:
1 2 3 4 5 6 7 8 | setGeneric (
"calculaMencao" ,
function (object) {
standardGeneric ( "calculaMencao" )
}
)
|
Em seguida, vamos definir um cálculo de função para cada tipo de aluno:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | setMethod (
"calculaMencao" ,
signature ( "Graduacao" ),
function (object) {
media<-(object@nota1+object@nota2+object@nota3)/3
return (media)
}
)
setMethod (
"calculaMencao" ,
signature ( "Posgraduacao" ),
function (object) {
media<-(object@nota1+object@nota2)/2
artigo<- ifelse (object@artigo == "" ,0,10)
nota<-media*0.5+artigo*0.5
return (nota)
}
)
|
Note que em ambas as definições dos métodos incluímos o método genérico
calculaMencao. O que muda entre eles é a assinatura (signature) e, consequentemente, a maneira como a função é calculada. Vamos agora criar alguns alunos seguindo a
classes S4 formada:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | joao <- new ( "Graduacao" ,
nome= "João Silva" ,
idade=22,
nota1=2.75,
nota2=8.78,
nota3=5.72)
maria <- new ( "Posgraduacao" ,
nome= "Maria Silva" ,
idade=27,
nota1=8.54,
nota2=3.21,
artigo= "Como programar em R" )
alex <- new ( "Posgraduacao" ,
nome= "Alexandre Silva" ,
idade=33,
nota1=2.15,
nota2=5.48,
artigo= "" )
|
Para não ter que repetir o mesmo código toda vez que desejarmos criar um objeto, podemos construir os
constructors:
1 2 3 4 5 6 7 8 9 | Graduacao <- function (nome, idade, nota1, nota2, nota3){
new ( "Graduacao" , nome=nome, idade=idade, nota1=nota1, nota2=nota2, nota3=nota3)
}
Posgraduacao <- function (nome, idade, nota1, nota2, artigo){
new ( "Graduacao" , nome=nome, idade=idade, nota1=nota1, nota2=nota2, artigo=artigo)
}
|
Podemos calcular a menção deles fazendo:
1 2 3 4 5 6 7 8 9 10 11 | resultadoJoao<- calculaMencao (joao)
resultadoJoao
resultadoMaria<- calculaMencao (maria)
resultadoMaria
resultadoAlex<- calculaMencao (alex)
resultadoAlex
|
Podemos ainda ter objetos que são oriundos de mais de uma classe, por exemplo, considere um aluno que faz tanto Graduação quanto Pós-graduação, podemos criar uma classe específica para ele:
1 2 | setClass ( "Maluco" ,
contains= c ( "Graduacao" , "Posgraduacao" ))
|
A criação dos objetos e cálculo das notas é feito da seguinte forma:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | sergioGraduacao <- new ( "Maluco" ,
nome= "Sergio Silva" ,
idade=22,
nota1=8.36,
nota2=9.12,
nota3=5.64)
sergioPosgraduacao <- new ( "Posgraduacao" ,
nome= "Sergio Silva" ,
idade=22,
nota1=3.45,
nota2=8.34,
artigo= "Não sei nada" )
resultadoSergio1<- calculaMencao (sergioGraduacao)
resultadoSergio1
resultadoSergio2<- calculaMencao (sergioPosgraduacao)
resultadoSergio2
|
É comum ainda criar para os métodos alguns pontos de validação dos valores de entrada, por exemplo, nenhuma nota pode ser negativa ou maior do que 10. Podemos incluir essas restrições fazendo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | setClass ( "Graduacao" ,
representation (
nota1= "numeric" ,
nota2= "numeric" ,
nota3= "numeric" ),
validity = function (object) {
if (object@nota1<0 | object@nota1>10 )
{
stop ( "A nota na prova 1 tem que ser válida." )
}
if (object@nota2<0 | object@nota2>10 )
{
stop ( "A nota na prova 2 tem que ser válida." )
}
if (object@nota3<0 | object@nota3>10)
{
stop ( "A nota na prova 3 tem que ser válida." )
}
return ( TRUE )
},
contains= "Aluno"
)
|
Nas
classes S4 de objetos temos algumas funções especiais:
- slotNames: fornece o nome dos slots.
- getSlots: fornece o nome dos slots e seus tipos.
- getClass: fornece o nome dos slots, seus tipos e das classes antecessoras.