Encapsulamento é uma das bases da Orientação a Objetos onde a idéia principal é tornar cada objeto auto-suficiente (na medida do possível). Com isso podemos gerar código com um grande índice de reuso, além de facilitar a manutenção.
Vamos tomar como exemplo um ComboBox:
Você adiciona o componente no Stage e insere os dados no mesmo (label, data, etc), certo? O componente é responsável por exibí-los. Assim, podemos dizer que você usa um ComboBox e tem acesso às propriedades necessárias para personalizá-lo ao seu modo (Talvez o combo do flash não seja o melhor exemplo de personalização, mas essa é outra história). Já pensou se você precisasse programar um código para que depois de um numero x de elementos fosse inserida uma rolagem no combo? Felizmente, neste conceito (e no do Flash, graças a Deus!), você não precisa. O combo é responsável pelos seus estados (lembre dessa palavra! Vamos lá, repita comigo: estado, estado, estado…), e é ele quem deve cuidar da sua rolagem independente do número de itens que possua.
Vamos supor que o nosso combo possua uma variável estática (que consequentemente tem o mesmo valor para todos os combos – ou em se tratando de OOP propriamente dita, para todas as instâncias do objeto) chamada MIN_ELEMENTS, que é responsável por armazenar o número mínimo de elementos visíveis, cuja declaração seria a seguinte:
public static var MIM_ELEMENTS:Number = 1;
Então, por descuido ou qualquer outro motivo alguém resolve escrever o código:
ComboBox.MIM_ELEMENTS = -10;
A variável é publica e pode ser acessada de qualquer lugar. Mas me diga, é possível renderizar -10 itens? Você acha possível que a alteração de um atributo como este poderia afetar o funcionamento do combo? É provável que sim. Não precisamos ter acesso a atributos deste gênero para utilizar o nosso objeto combo, mas é um dado importante dentro do mesmo. Assim a declaração correta seria:
private static var MIM_ELEMENTS:Number = 1;
Agora esse atributo só é visível dentro da classe e só pode ser alterado internamente.
Vamos a outro exemplo. Temos uma classe Pessoa e um de seus atributos é sexo e seu conteúdo pode ser feminino ou masculino.
class Pessoa { public var sexo:String; // continua o codigo // ... } var p:Pessoa = new Pessoa(); p.sexo = "Maria";
A variável sexo é pública e do tipo String portanto poderia aceitar tranquilamente a String“Maria”, entretanto, isso pode – e provavelmente irá – comprometer o funcionamento do nosso objeto, tendo em vista que o sexo “Maria” definitivamente não existe. Assim, utilizamos recursos de encapsulamento de OOP para proteger o nosso objeto. Os getters e os setters.
class Pessoa { private var _sexo: String; public function get sexo():String { return _sexo; } public function ser sexo(value:String) { value = value.toLowerCase(); if (value == "feminino" or value="masculino") _sexo = value; // caso nao fosse atribuido poderia ser disparado um evento, // ser gerada uma excessao, // exibir uma mensagem de erro e por ai vai. } }
No exemplo acima, garantimos que será inserido apenas um dado válido. E o getter? Bom, se você restringe o acesso a um dado e ele precise ser visto fora do objeto, é necessário disponibilizá-lo (se e somente se ele realmente precisa ser visto de fora). Mas não confunda! O getter pode conter outras coisas além do retorno do atributo.
Geralmente quando se começa a aprender OOP (seja para criar o hábito, começar a identificar necessidades, ou qualquer outra coisa que se possa querer com isso) se indica utilizar atributos privados para tudo (ou quase) e a criação de getters/setters de todos eles. Isso porque quando se vem de uma linguagem procedural se pode fazer tudo com todos os “atributos”, não existe encapsulamento e literalmente “todo mundo é de todo mundo”. Então tenta-se a criar (ou modificar) uma cultura. Se isso é certo ou não… é um jeito (e a maioria dos programadores em algum momento passam por essa fase, depois passamos a fase de nos livrar do hábito do excesso).
A identificação das necessidade da utilização desses metodozinhos vem com a experiência. É preciso saber identificar quando o usuário pode inserir um dado diretamente, quando ele pode ver um dado, quando ele pode inserir algum dado mas com restrições, quando você precisa saber se um dado é inserido, etc… Uma forma de saber isso antes de colocar a mão na massa é a modelagem. O código abaixo por exemplo é apenas uma maneira burocrática de “gerar uma variável pública”.
private var _sexo: String; public function get sexo():String { return _sexo; } public function set sexo(sexo:String) { _sexo = sexo; }
Então… Vamos modelar, modelar e modelar?