Encapsulamento
Fevereiro 4, 2008
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, rss). 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 OO 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 OO 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(sexo:String){
sexo = sexo.toLowerCase();
if (sexo == "feminino" or sexo="masculino")
_sexo = sexo;
// 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 POO (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 em POO. É 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 é uma maneira mais 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? Ok! Você “não tem tempo pra isso” ou “não gosta de fazer isso” ou qualquer outro “ou“. Neste caso, eu simplesmente aconselho que comece com todas os atributos privados e vá filtrando conforme desenvolve a classe (dentre os males, penso que este é o menor), mas acredite: modelar é mais rápido.