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.

Verdadeiro ou falso: tipos

Janeiro 25, 2008

Se considerarmos,

var a:String = new String(“string”);
var b:String = new String(“string”);
var c:String = “string”;
var d:String = “string”;
Então:

1) a == b ?

2) a === b?

3) c == a?

4) c === a?

5) c == d?

6) c === d?

Respostas (publicado em 03/02/08):

Começando pela diferença entre os operadores de igualdade.

O operador de igualdade estrita (===) é como o operador de igualdade, com uma diferença importante: o operador de igualdade estrita não executa a conversão de tipo. Se os dois operandos forem de tipos diferentes, o operador de igualdade estrita retornará false (MACROMEDIA, Guia de Referência do ActionScript Flash MX 2004, pag. 44).

A variável a, assim como a variável b são objetos do tipo String. Ao serem comparadas com operador estrito ou não, sempre retornarão false.

1) a == b // false
2) a === b // false

Isso porque a e b são objetos diferentes. Mesmo sendo instâncias da mesma classe e contendo atributos iguais, eles possuem identidade diferentes, são armazenados em lugares diferentes da memória, assim as variáveis a e b são referências a objetos String e contém o endereço de memória de cada um dos objetos criados. Dessa forma podemos concluir que, quando comparamos a e b, sempre será false, pois em seu conteúdo não constam valores literais, mas distintos endereços de memória.

Então, como comparar os seus conteúdos?

a.valueOf() === b.valueOf() ou a.valueOf() == b.valueOf()

Mais uma consulta ao help do flash e temos, valueOf - Método; retorna o valor primitivo do objeto especificado. Se o objeto não tiver um valor primitivo, o objeto é retornado.

Já as variáveis c e d são tipos primitivos e possuem em seu conteúdo um valor literal que lhes foi atribuído. Veja mais um trecho do Guia de Referência AS:

Os tipos de dados descrevem que tipos de informações um elemento do ActionScript ou variável pode conter. Existem dois tipos de dados internos no Flash: primitivo e referência. Os dados do tipo primitivo — String, Number e Boolean — têm um valor constante e, portanto, podem manter o valor real do elemento que representam. Os de referência— MovieClip e Object — têm valores que podem ser alterados e, portanto, contêm referências ao valor real do elemento.

Assim, considerando que c e d armazenam um conteúdo e não uma referência a uma posição de memória, podemos afirmar que:

5) c == d // true
6) c === d //true

Com base em tudo isso, podemos concluir também que:

4) c === a // false

Considerando que estamos comparando uma referência de memória com um tipo primitivo.

Já no caso:

3) c== a // true

É verdadeiro porque o operador de igualdade (==) analisa conteúdos e faz a conversão de tipo. Como o conteúdo é idêntico, o resultado é verdadeiro, independente de serem valores literais, variáveis ou referências. Então você me pergunta, porque a== b não é verdadeiro então? E a resposta é… Como o operador de igualdade considera que c == a e String(a) == b são verdadeiros?

Objetos são instâncias de classes, que determinam qual informação um objeto contém e como ele pode manipulá-la. É através de objetos que (praticamente) todo o processamento ocorre em aplicações desenvolvidas com linguagens de POO.

Manipulando objetos

Quando declara-se uma variável cujo tipo é o nome de uma classe, como em:

var nome:String;

não está se criando um objeto dessa classe, mas simplesmente uma referência para um objeto da classe String, a qual inicialmente não faz referência a nenhum objeto válido:

Quando um objeto dessa classe é criado, obtém-se uma referência válida, que é armazenada na variável. Por exemplo:

   Nome = new String(“Nova instância”);

Nome é uma variável que armazena uma referência para um objeto específico da classe String, cujo conteúdo é “Nova instância”:

A variável nome mantém apenas a referência para o objeto e não o objeto em si. Assim, uma atribuição como

   var Nome2:String = Nome;

não cria outro objeto, mas simplesmente uma outra referência para o mesmo objeto

Referência:
http://www.dca.fee.unicamp.br/cursos/PooJava/objetos/manipul.html
O link acima está com explicações e exemplo de codigos para Java.