Três são os conceitos básicos de programação a orientação a objeto: Herança, polimorfismo e encapsulamento. Neste artigo vamos ver como aplicar o encapsulamento no seu código em C!
A programação orientada a objeto nos concede muitas vantagens. O encapsulamento nos permite que só exista uma forma de acessar nossos dados, os famosos “getters”, e uma forma de alterá-los, os famosos “setters”. Não existe acesso direto ao atributo! Isto nos dá segurança pois podemos fazer validações antes de alguém acessar ou alterar o nosso dado.
Outra vantagem do encapsulamento é que os detalhes internos de implementação são escondidos do resto do código. Desta forma eles podem ser alterados dependendo de plataforma ou situação sem que o resto do software sofra alterações.
Exemplo de Encapsulamento
Vamos imaginar a classe Usuario, o Usuario possui um nome, um login e uma senha. Além destes atributos ele também possui o método “autenticar” que retorna verdadeiro se a combinação de login e senha for verdadeira. Os getters e setters não são colocados no diagrama de classe para fins de visibilidade. Mas também considere a existência dos métodos getNome, getLogin, getSenha, setNome, setLogin e setSenha.
No nosso caso a classe Usuario em C consiste de dois arquivos: um .h e um .c. No caso, usuario.c e usuario.h.
Segundo as boas praticas da orientação a objeto os atributos de uma classe são internos a ela e só ela os conhece. Ou seja, a estrutura de dados com os atributos Nome, Login e Senha só pode ser conhecida por quem a utiliza, no nosso caso o arquivo usuario.c:
#include "usuario.h"
#include
#define TAM_MAX_SENHA 10
struct usuario{
char* nome;
char* login;
char* senha;
};
struct usuario* usuario_new(void)
{
struct usuario* usr;
usr = malloc(sizeof(struct usuario));
return usr;
}
int usuario_del(struct usuario* usr)
{
free(usr);
return 1;
}
int usuario_autentica(struct usuario* usr, char* senha)
{
if (strcmp(usr->senha, senha, TAM_MAX_SENHA))
return 1;
else
return 0;
}
char* usuario_getSenha(struct usuario* usr)
{
return usr->senha;
}
char* usuario_getLogin(struct usuario* usr)
{
return usr->login;
}
char* usuario_getNome(struct usuario* usr)
{
return usr->nome;
}
int usuario_setSenha(struct usuario* usr, char* senha)
{
usr->senha = senha;
return 1;
}
int usuario_setLogin(struct usuario* usr,char* login)
{
usr->login = login;
return 1;
}
int usuario_setNome(struct usuario* usr, char* nome)
{
usr->nome = nome;
return 1;
}
Porém os objetos do tipo “Usuario” devem poder ser utilizados por todos que o desejarem. Por isso uma declaração da nossa estrutura de dados é feita no nosso arquivo usuario.h, porém é declarado como uma estrutura opaca, ninguém sabe o que realmente tem dentro dela a não ser nosso .c.
Arquivo usuario.h:
struct usuario; /* retorna um objeto do tipo usuario */ struct usuario* usuario_new(void); /* deleta o objeto do tipo usuario */ int usuario_del(struct usuario* usr); /* verifica se a senha eh igual */ int usuario_autentica(struct usuario* usr,char* senha); /* retorna a senha do usuario */ char* usuario_getSenha(struct usuario* usr); /* retorna o login do usuario */ char* usuario_getLogin(struct usuario* usr); /* retorna o nome do usuario */ char* usuario_getNome(struct usuario* usr); /* seta a senha do usuario */ int usuario_setSenha(struct usuario* usr, char* senha); /* seta o login do usuario */ int usuario_setLogin(struct usuario* usr,char* login); /* seta o nome do usuario */ int usuario_setNome(struct usuario* usr, char* nome);
Para testar vamos utilizar este main.c:
#include
#include
#include "usuario.h"
int main()
{
struct usuario* usr;
usr = usuario_new();
usuario_setSenha(usr, "testando");
printf("Senha: %s\n",usuario_getSenha(usr));
return 0;
}
É impossível um arquivo que não o usuario.c acesse os atributos e métodos desta classe e esses acessos são controlados pelos nossos getters e setters via usuario.c. Se adicionarmos esta linha ao arquivo main.c veremos um erro:
/* A linha abaixo ocasiona em erro de compilacao, o main nao conhece os atributos de usuario */
printf("Senha: %s\n",usr->senha);
Se formos desenvolver para um sistema embarcado Bare metal e não quisermos utilizar alocação dinâmica de memória podemos simplesmente mudar a definição da nossa struct para algo do tipo:
struct usuario{
char nome[TAM_MAX_NOME];
char login[TAM_MAX_LOGIN];
char senha[TAM_MAX_SENHA];
};
e reescrever nossos métodos no arquivo usuario.c, eliminando os métodos de alocação e liberação de memória.
Observação: Diversas verificações no arquivo usuario.c foram deixadas de lado para fins didáticos. Verificações como se o objeto é nulo antes de dar um get ou set, ou ainda se o malloc/free foram realizados com sucesso.
Aprenda mais
Orientação a objeto em C: Polimorfismo
