O TEMA DO FÓRUM ESTÁ EM MANUTENÇÃO. FEEDBACKS AQUI: ACESSAR

Encapsulamento - Programação Orientada a Objetos

Iniciado por MayLeone, 29/09/2018 às 21:10


O que é?
O encapsulamento em programação é conhecido como um dos pilares da programação orientada a objetos, do ato de encapsular, ou seja, proteger ou esconder algo.
Este conceito está muito ligado com relação à implementação de membros de classes, onde por vezes, se faz necessário a 'proteção' de algum atributo da mesma, ou simplesmente o desejo de querer esconder detalhes de implementação.
Com o encapsulamento, podemos restringir o acesso e a escrita dos atributos em classes, dando uma maior segurança e flexibilidade ao código.

Para ilustrar um exemplo de utilização do encapsulamento em C#, iremos criar uma classe pública chamada "Pessoa"e nela iremos definir três atributos quaisquer: nome, cpf e idade:



Perceba que para esta classe, o modificador de acesso dos atributos é público, e por isso, eu posso manipular livremente os mesmos externamente, através da classe padrão "Program":



Veja que da forma como está, podemos colocar valores à vontade no atributo (setar valores) e também podemos acessá-los (ler valores), através do Console.WriteLine, ou seja, esses atributos não estão encapsulados e possivelmente poderão ser manipulados de forma incorreta, como por exemplo, colocar um valor negativo para a idade:



O código rodará sem problemas, pois o tipo da variável 'int' aceitará valores negativos, porém, sabemos que não há como alguém possuir uma idade negativa.
Esse acesso direto do atributo de uma classe pode se tornar um problema (como vimos acima), pois o seu acesso se encontra público.

Podemos tentar resolver este problema fazendo com que o modificador de acesso dos atributos se tornem privados, ou seja, apenas a própria classe poderá manipulá-los:



Isso resolveria o nosso problema em partes, visto que os atributos possuem apenas acesso interno, mas agora eles não serão reconhecidos externamente, acarretando erros:



Então devemos ter algo que seja o intermédio entre os atributos privados da classe, e o seu acesso externo.
Quem faz este trabalho são o que chamamos de métodos acessores:

Métodos acessores:
Os métodos acessores irão ser definidos na classe que possui os atributos que queremos ter acesso. Eles permitirão que possamos ler e escrever valores nos atributos privados da classe, sem que façamos tais procedimentos diretamente nos mesmos, criando assim, um maior controle no código.
Esses métodos devem ser públicos (para terem acesso externo) e consistem em devolver o valor de um atributo como retorno (get) ou permitir que coloquemos valores neles (set).
Vamos criar os métodos acessores dos atributos de nome e cpf:



Note que os métodos 'Get' possuem um valor de retorno que é igual ao tipo do atributo a ser acessado e não possui parâmetros, sua única função é retornar o valor do atributo. Já os metódos 'Set' não possuem retorno e o parâmetro é do mesmo tipo daquele atributo, sua função é fazer com que o mesmo receba o valor do parâmetro passado.

Observe que agora podemos ler e escrever valores mesmo os atributos sendo privados, porém estamos fazendo isto de forma segura e sem realmente manipulá-los diretamente, pois os métodos acessores que estão implementados dentro da classe fazem esta tarefa, já que para ler um valor ou escrever precisamos obrigatoriamente chamá-los:



Agora para implementarmos o atributo 'idade' podemos utilizar o método acessor 'Set' para restringir o valor negativo, dessa forma:



O que fizemos aqui através do acessor 'Set' é impedirmos que um valor negativo seja colocado para o atributo de idade, realizando uma simples condição: caso o parâmetro passado for um valor negativo,  'idade' irá receber zero, caso não, receberá o valor do parâmetro passado, dessa forma, impedimos que nosso atributo seja utilizado de forma incorreta, veja:



No output podemos perceber que a restrição está funcionando corretamente:



Então além de protegermos o atributo ainda podemos criar regras de implementações para ele, eis então as vantagens do encapsulamento.

Properties:
Em C# temos também a sintaxe das Properties (propriedades), ou seja, palavras reservadas para podermos encapsular nossos atributos sem precisar escrever métodos.
Essas palavras reservadas estão ligadas aos métodos acessores Get e Set, então para escrever uma propriedade, basta fazer o seguinte:



Para criar essa propriedade definimos a mesma como pública, com o mesmo tipo do atributo a ser acessado e com o nome semelhante, porém seguindo a notação Pascal Case que utilizamos para nomeação de métodos e classes. Dentro do escopo desta propriedade nós definimos os acessores Get e Set através das palavras reservadas, e então implementamos seus comportamentos: no Get apenas retornamos o valor do atributo desejado, enquanto no Set permitimos que algo seja escrito neste atributo.
A palavra reservada "value" pode funcionar como se fosse o parâmetro de um método, ou seja, o que foi inserido naquela propriedade através do acessor Set irá ser passado para 'value'.
*Implemente da mesma forma o atributo 'cpf'.

Podemos então implementar o atributo "idade" com aquela restrição que tínhamos visto anteriormente:



E agora através das propriedades podemos fazer acesso externo aos membros da classe, sem precisar especificar seus métodos acessores:



Auto Implemented Properties:

A partir da versão 3.0 do C# nós temos as propriedades auto implementadas, ou seja, um jeito mais compacto e menos trabalhoso de declarar as propriedades.
Para criar este tipo de propriedade, basta delimitar seu escopo às chaves {} e dentro delas apenas escrever as palavras reservadas "get" e "set", finalizando com ponto e vírgula, dessa forma:



Veja que como as propriedades "Nome" e "Cpf" não possuem nenhuma implementação específica, podemos defini-las com as propriedades auto implementadas diretamente, o que deixa o código menor e dá menos trabalho para escrever, já a propriedade "Idade" fica como estava antes pois ela recebe uma implementação específica.

Modificador de acesso nos acessors:
Por padrão, os acessores das propriedades são definidos como públicos (public) mas se você quiser restringir esse acesso, por exemplo, fazer com que determinada propriedade possa apenas ser lida e não escrita, basta fazer com que o modificador de acesso do "set" fique privado, impedido acesso externo, ou seja, essa propriedade apenas poderá ser lida externamente e não poderá ser setada:



Dessa forma, a propriedade "BonusSalarial" não poderá ter seu valor escrito (pois o set está private), mas poderá ser lida. Seu valor foi setado internamente através do construtor da classe.

Manipulando essa propriedade:



Final:
E aqui chega mais um final de aula! Espero que tenham gostado e até a próxima.

Excelente aula como sempre, May o/ Ansioso para ver mais de suas descobertas, haha'
Só alguns pontos que gostaria de ressaltar:

Spoiler

Signed e Unsigned:

Sobre o exemplo da idade não poder ser negativa, considere usar [emphasys]uint[/emphasys] ao invés de [emphasys]int[/emphasys]. Isso é algo que passa muito despercebido por iniciantes na linguagem, mas usar o tipo de armazenamento correto faz bastante diferença. Digamos que estou criando uma struct que represente a resolução da tela. Observe o seguinte exemplo:

Essa é uma struct que contém apenas valores primitivos que preciso enviar para código não-gerenciado (feito em C++, por exemplo). Veja que não é possível criar uma resolução com valores negativos, e assim que eu enviar a struct, os valores dela precisarão ser limitados a (0, 2147483647).
Uma boa prática nesse caso seria utilizar unsigned int, ou uint em C#:

Isso torna visível a outros programadores que aquele valor nunca pode ser menor que 0.

Fields e Properties:

A menos que esteja trabalhando com structs, prefira utilizar Properties para acesso público e Fields para valores privados.
Em C#, qualquer valor que não possua modificador de acesso por padrão é privado.

Lembrando que no segundo exemplo o campo Name só pode ser definido na declaração ou no constructor. Se você quiser modificar o valor depois, considere usar uma propriedade.

Segurança:

Em .NET, nenhum código que você cria é verdadeiramente privado e interno, visto que tudo é compilado para CIL. É um pequeno preço a se pagar por usar código gerenciado.
Exemplo de acesso a um método privado com Reflection.

Neste exemplo, não apenas criamos uma instância de um tipo interno, mas também chamamos o seu método privado.
Não se enganem, isso não quer dizer que você não precise criar código com modificadores de acesso, pelo contrário, crie e deixe visível apenas o que o usuário final deva utilizar. Estou apenas mostrando que é possível obter informações privadas e isso fica como responsabilidade total de quem for utilizar seu código de tal forma.
[close]

É nozes, May o/ Espero ver mais conteúdo aê xD

C# me deu coisas no começo, quando fui aprender os tais assessores. Get/set também até que eu entendesse o conceito. Enfim, ótima aula. o/