Dominando action script3

151

Transcript of Dominando action script3

Page 1: Dominando action script3
Page 2: Dominando action script3

Dominando

Action Script 3.0

Daniel Schmitz

Versão 1.1

Atenção

Este ebook não é gratuito. Contribua com a qualidade desta obra

e com o desenvolvimento de novos livros digitais. Não

retransmita este documento. Ajude o autor a criar mais obras de

qualidade e ajude-o a pagar as suas contas

Caso tenha obtido esta obra por outros meios, você

ainda pode me ajudar realizando a compra do mesmo, no site:

www.flex.etc.br/dominando-action-script-3

Obrigado!

Page 3: Dominando action script3

A minha linda esposa Jândria

Page 4: Dominando action script3

Convenções utilizadas nesta obra

Dica: Informa uma dica ao leitor.

Atenção: Informa uma mensagem de atenção ao leitor.

// ......... Indica que existe código fonte, mas não será exibido porque não é

relevante naquele momento.

trace( variável ) // saída da variável As vezes, colocamos o resultado do

comando trace como comentário após as duas barras.

Negrito Indica alterações no código fonte, como por exemplo, uma nova

propriedade adicionada a um componente.

, , até São referências ao código realizadas para um melhor

entendimento. Sempre que houver estas referências existirá uma explicação

após o código.

Suporte

Acesse www.flex.etc.br para conferir as últimas novidades do livro,

capítulos extra, código fonte, etc. Você também pode enviar um email para o

autor, caso tenha dúvidas sobre esta obra.

Daniel Pace Schmitz

[email protected]

Twitter: @Daniel_Schmitz

Page 5: Dominando action script3

Conteúdo

Capítulo 1 - Introdução .................................................................................. 13

O que é Action Script? ............................................................................... 13

Action Script 2.0 e Action Script 3.0 ......................................................... 14

O papel do Flash Player ............................................................................. 14

O Adobe Flash Builder 4 ............................................................................ 15

Instalação do Adobe Flash Builder ......................................................... 16

Obtendo uma licença gratuita – para uso não comercial ......................... 17

Criando o “Hello World” ........................................................................... 18

O comando trace() ..................................................................................... 22

Conhecendo Action Script 3.0 ....................................................................... 24

Entendendo o HelloWorld .......................................................................... 24

Variáveis ..................................................................................................... 26

Tipos de variáveis ....................................................................................... 27

String ....................................................................................................... 27

O método toString() ................................................................................ 29

Number, int e uint .................................................................................... 30

Boolean .................................................................................................... 31

Date ......................................................................................................... 31

Object ...................................................................................................... 32

Constantes .................................................................................................. 33

Page 6: Dominando action script3

Escopo ........................................................................................................ 33

Visibilidade ................................................................................................ 34

Operadores ................................................................................................. 35

Precedência de operadores ...................................................................... 36

Condicionais ............................................................................................... 36

if .............................................................................................................. 37

if + else .................................................................................................... 39

If + elseif + else ....................................................................................... 39

Switch ...................................................................................................... 40

Operador ternário (ou condicional) ......................................................... 42

Loops 43

for ............................................................................................................ 43

for each ... in ............................................................................................ 44

while ........................................................................................................ 44

do ... while ............................................................................................... 45

Pulando ou saindo do loop ......................................................................... 45

Funções ....................................................................................................... 47

Função ou método? ................................................................................. 48

Parâmetros ............................................................................................... 48

Parâmetros rest (...) ................................................................................. 49

Argumento padrão ................................................................................... 50

Função anônima ...................................................................................... 51

Funções recursivas .................................................................................. 53

Page 7: Dominando action script3

Try...catch...finally e throw ........................................................................ 53

Action Script 3.0 e Orientação a Objetos ....................................................... 55

Entendendo OO .......................................................................................... 55

Classe 58

Propriedades get/set .................................................................................... 62

Métodos e sobrecarga (override) ................................................................ 65

Métodos e variáveis estáticos ..................................................................... 67

Interfaces .................................................................................................... 68

Como criar uma interface ........................................................................ 68

Como associar uma interface a uma classe ............................................. 70

Aplicando mais interfaces a uma mesma classe ...................................... 72

Acoplamento e interfaces ........................................................................ 73

Classes dinâmicas ....................................................................................... 77

Conhecendo a API ......................................................................................... 79

String 79

Array 82

Date 90

Math 92

Object 93

Eventos ........................................................................................................... 96

O que é um evento? .................................................................................... 96

Definições ................................................................................................... 96

Como trabalhar com eventos ...................................................................... 97

Page 8: Dominando action script3

Como criar eventos ..................................................................................... 99

Integração com o Flex .................................................................................. 105

Criando o projeto Flex .............................................................................. 105

Importando bibliotecas ............................................................................. 107

Criando sua própria biblioteca Action Script ........................................... 111

Adicionando a biblioteca no projeto Flex ................................................ 113

Como trabalhar com Action Script e MXML .......................................... 115

Como estender componentes .................................................................... 119

Aplicando padrões de projeto ...................................................................... 121

Entendendo Padrões de Projeto ................................................................ 121

Factory ...................................................................................................... 126

Singleton ................................................................................................... 132

Observer ................................................................................................... 137

Exemplo real com Observer .................................................................. 144

Combinando Padrões (Factory + Observer) ............................................. 147

Para finalizar... ......................................................................................... 155

Page 9: Dominando action script3

Capítulo 1 - Introdução

A tecnologia Flash evoluiu de forma a estar presente em mais de 98% dos

navegadores no mundo todo. Inicialmente como uma tecnologia para

“desenhar animações”, o Flash evoluiu diversos conceitos, dentre eles a sua

linguagem base.

Quando falamos em linguagem base do Flash estamos dizendo Action Script.

Todas aquelas animações dos banners Flash e dos sistemas em Flex são

movidos por esta linguagem, na qual iremos aprender os seus principais

conceitos nesta obra.

O que é Action Script?

Basicamente é uma linguagem de programação, como PHP, C# ou Java. É

claro que possui suas diferenças, mas o seu padrão ECMAScript3 garante

uma certa semelhança às linguagens derivadas do C.

É um pouco óbvio que você saiba o que é Action Script, pois comprou um

livro que fala exatamente deste assunto, por isso não vamos nos aprofundar

nisso. Rapidamente, podemos dizer que o Action Script é uma linguagem que

possui uma dinâmica orientada a objetos, e possui a maioria dos comandos

que todas as linguagens de programação têm, tais como o if, while e for.

Além disso, o Action Script possui funcionalidades extras, graças à rica

biblioteca de recursos do Flash Player. Dentre elas podemos destacar:

Carregar imagens bitmap;

Executar som e vídeo;

Capturar o som do microfone e o vídeo da webcam;

Page 10: Dominando action script3

Desenhar linhas, figuras (retângulo, elipse...), fazer preenchimentos

com gradiente e aplicar máscaras, definir transparência;

Carregar e manipular dados XML;

Interagir com o usuário capturando eventos como o click do mouse ou

teclas do teclado;

Realizar animações em objetos;

Trabalhar com dados binários;

Além desse “básico”, utilizando as bibliotecas do Flash e do Flex, centenas

de novas funcionalidades são adicionadas ao Action Script.

Dica: Quer conhecer todas as classes do Action Script? Apresentamos então o melhor caminho para isso, se chama “Action Script 3.0 Reference” e está disponível neste endereço:

http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/index.html

Action Script 2.0 e Action Script 3.0

Existem basicamente duas versões do Action Script: 2.0 e 3.0. A versão 2.0

está ligada às versões antigas do Flash, e por isso não serão vistas nesta obra.

Estaremos abordando exclusivamente a versão 3.0 do Action Script, e quando

você ler “Action Script” em nosso livro, saiba que é “Action Script 3.0”.

O Action Script 3.0 já é usado no Flash CS 5 e sempre foi usado no Flex,

então não existe a necessidade de analisarmos diferenças entre estas duas

versões.

O papel do Flash Player

O Action Script 3.0 é a base para os sistemas em Flex e as animações no

Flash. Mas como estes códigos podem ser executados em um navegador web

se o usual é HTML e JavaScript? Para isso existe um plugin chamado Flash

Player, que atualmente está na versão 10.0.

Page 11: Dominando action script3

Felizmente o Flash Player é um plugin consagrado no mercado, presente em

mais de 98% dos navegadores no mundo. É um produto maduro, com mais

de 10 anos de existência.

O Flash Player funciona como uma máquina virtual, assim como no Java. Ou

seja, quando criamos códigos para o Flash Player, não estamos preocupados

com a versão do sistema operacional ou com o navegador do cliente, pois

estamos criando código para o Flash Player. Ele será responsável em

reproduzir o nosso código de acordo com o sistema operacional/navegador.

Isso é muito bom, porque podemos programar a vontade sem a necessidade

de testar navegadores (algo necessário com JavaScript).

O Flash Player trabalha com um arquivo compilado chamado swf. Ou seja,

todos os arquivos que criarmos com a extensão “.as”, ao compilarmos, resulta

em um único arquivo swf. Se este processo é complexo para você, fique

tranqüilo, utilizando uma IDE como o Flash Builder, teremos tudo isso sem

maiores problemas. Falaremos do Flash Builder no próximo capítulo.

Além do Flash Player poder executar todo o seu código, ele também contém

um conjunto de códigos prontos que podemos usar a vontade, chamado de

API do FlashPlayer. Por exemplo, se quisermos obter uma instância da

webcam do usuário (para tirar um foto), será pela API do Flash Player que

conseguiremos isso. O mesmo vale para capturar as teclas do teclado ou o

click do mouse.

Dica: Quer ver todas as classes pertencentes ao Flash Player, juntamente com o Flex? Acesse http://flex.org/poster e faça o download.

O Adobe Flash Builder 4

O Flash Builder 4 é a melhor IDE para aprendermos Action Script. Uma IDE

(Integrated Development Enviroment – Ambiente integrado de

desenvolvimento) é um programa de computador que traz diversas

facilidades para desenvolvermos código.

Page 12: Dominando action script3

Relembrando, o Flash Player, bem como o Action Script e todo o framework

Adobe Flex são gratuitos. Ou seja, você pode construir aplicações em

Flash/Flex sem gastar nada, bastando apenas usar um editor de códigos e o

compilador. Este não será o nosso caso. Nesta obra, iremos utilizar o Flash

Builder – que é uma IDE paga, mas possui 60 dias de avaliação, e ainda

possui versões gratuitas para estudantes e para pessoas que estejam

financeiramente sem recurso (iremos mostrar como conseguir isso ainda

neste capítulo).

Ou seja, o Flash Builder é a IDE perfeita para você que está aprendendo

Action Script (ou Flex), e será a IDE perfeita quando você começar a criar

aplicações em Flex.

Instalação do Adobe Flash Builder

Para instalar o Adobe Flash Builder 4, acesse o seguinte endereço:

http://www.adobe.com/go/try_flashbuilder

Na página que surge, escolha a versão “English | Standalone Windows”, e

clique em “Download Now”. Talvez seja necessário realizar um login no site

da Adobe. Se você ainda não tiver uma conta, deverá criar uma.

Após realizar o download, execute o arquivo de instalação

(FlashBuilder_4_LS10.exe ou semelhante) e extraia os arquivos para algum

diretório em seu computador. Após extrair os arquivos, acesse o diretório e

execute o arquivo Set-up.exe. Surge então um assistente de instalação, que irá

lhe guiar neste processo. Após instalar o Flash Builder, execute-o. Surgirá

uma tela de licença de software, no qual exibe quantos dias restantes você

tem de direito de acesso, além de outra tela para que você, caso deseja, possa

se conectar na conta da Adobe.

Após instalado, a tela inicial do Flash Builder é exibida conforme a figura a

seguir, onde temos na janela principal chamada de “Start Page” com alguns

tutoriais sobre Flex. No lado esquerdo, temos a janela “Package Explorer”,

Page 13: Dominando action script3

que mostra o seu projeto juntamente com diversas funcionalidades que serão

vistas a medida que formos apresentando os exemplos sobre Action Script.

Na parte inferior, a janela problemans, que exibe possíveis erros no seu

código.

É válido lembrar que quando o Adobe Flash Builder 4 é instalado, o plugin

do Flash Player (versão 10) também é instalado, inclusive na versão Debug,

que exibe erros de execução de código.

Obtendo uma licença gratuita – para uso não comercial

Para obter a licença gratuita do Flash Builder, você pode realizar um cadastro

no site da Adobe como estudante (Escolas e faculdades podem obter licenças

para os seus laboratórios também), no seguinte endereço:

Page 14: Dominando action script3

http://www.adobe.com/devnet/flex/free/index.html

Acessando esta página, basta preencher o cadastro e aguardar um email com

a licença. Repare que no campo “Reason for applying”, você pode usar o

item “unemployed”, que significa desempregado.

Criando o “Hello World”

Vamos usar o Adobe Flash Builder para criamos o nosso primeiro código.

Através dele iremos aprender diversos conceitos, mesmo sem conhecer

profundamente a linguagem.

Com o Flash Builder aberto, navegue até o item de menu File (canto superior

esquerdo), New, Action Script Project:

Page 15: Dominando action script3

Veja que temos também projetos do Adobe Flex e do Flash Professional. Ao

selecionarmos ActionScript Project, surge a seguinte tela:

Page 16: Dominando action script3

Nesta tela, devemos inserir o nome do projeto, no campo “Project Name”.

Deixe marcado o item “Use default location”, e deixe a versão do Flex SDK

como a padrão (default). Clique no botão “Finish” para criar o projeto.

Neste momento o projeto “HelloWorld” é criado, e temos a seguinte tela:

Page 17: Dominando action script3

Vamos olhar novamente para o Package Explorer. Agora temos o projeto

HelloWorld criado, juntamente com algumas pastas. Neste momento,

podemos olhar somente para a pasta src, onde temos o arquivo

HelloWorld.as, que representa a classe HelloWorld.

A aba Outline mostra o “esqueleto” da classe HelloWorld, onde poderemos

navegar através dos métodos e propriedades da classe com mais facilidade.

Na janela principal, temos a classe HelloWorld, com pouco mais de 10 linhas

de código.

Vamos inserir algum código nesta classe. Na linha 9 (da figura anterior),

temos um método chamado HelloWorld. Inicialmente, vamos aceitar que este

método sempre será executado quando executarmos a aplicação. Vamos

inserir o seguinte código:

Page 18: Dominando action script3

package

{

import flash.display.Sprite;

public class HelloWorld extends Sprite

{

public function HelloWorld()

{

trace("Hello World");

}

}

}

No método HelloWorld, em , usamos o comando trace para imprimir

alguma coisa na janela de Debug, chamada de Console. Este comando será

muito utilizado, e merece algumas considerações importantes

O comando trace()

O comando trace() é usado para imprimir informações na janela Output do

Flash Builder . Uma consideração muito importante sobre o trace(), é que

ele funciona somente quando executamos a aplicação no modo Debug.

O modo Debug é um modo de execução especial do Flex, que é executando

clicando no ícone em destaque da figura a seguir:

Este ícone está localizado na parte superior do Flash Builder. Vamos então

executar o projeto Hello World. Clique no ícone e aguarde o Flex abrir o

navegador web. Porque isso? Por que o Flash Builder irá executar a aplicação

HelloWorld através do arquivo HelloWorld.swf, que deverá ser executado no

navegador. Assim que o navegador abrir, volte ao Flash Builder e verifique

se a janela “Console” está aberta, com a linha “Hello World” sendo exibida,

conforme a figura a seguir:

Page 19: Dominando action script3

Veja na parte inferior do Flash Builder que a aba Console ficou ativa, e na

primeira linha temos o “Hello World” que foi criado através do comando

trace(“Hello World”). Se a aba Console não apareceu automaticamente,

acesse o menu Window, Console. Se não apareceu o “Hello World”,

possivelmente você clicou no boto run ( ) e não no botão Debug ( ).

Lembre!! O comando trace() funciona somente no modo Debug

Talvez você possa estar se perguntando, porque o HelloWorld não surgiu no

navegador? Isso acontece por que o comando trace() apenas envia um

comando para o debugger informando o texto que está em seu parâmetro, e

somente isso. O trace() em nenhum momento cria uma algo visual na tela.

Page 20: Dominando action script3

Conhecendo Action Script 3.0

Neste capítulo iremos aprender todos os conceitos básicos sobre o Action

Script, e sobre programação em geral. Nossa primeira tarefa será entender

melhor como o exemplo HelloWorld funciona e a partir dele compreender

diversos conceitos sobre programação.

Entendendo o HelloWorld

O programa HelloWorld que criamos no capítulo anterior apresenta algumas

particularidades até agora desconhecidas. Vamos novamente olhar para o

código do HelloWorld:

package

{

import flash.display.Sprite;

public class HelloWorld extends Sprite

{

public function HelloWorld()

{

trace("Hello World");

}

}

}

Este código é o padrão para qualquer tipo de programa ActionScript puro.

Quando criamos um programa em Flash, Flex ou Air, não estaremos mais

seguindo esse código, mas é interessante conhecer a estrutura de um

programa Action Script puro.

O código inicial começa com a definição o Package (). Um Package é um

recurso do Action Script para separar diversas classes em pacotes distintos,

assim como acontece no Java, PHP (versão 6) ou C#. Imagine que cada

Page 21: Dominando action script3

classe em um sistema seja um livro. O sistema todo é uma biblioteca. Agora

imagine que o package seja a categoria dos livros (suspense, literatura, exatas

etc.) e veja que, um sistema sem packages é como uma biblioteca sem

prateleiras ordenadas pelas categorias dos livros.

Na prática, os packages separam as classes pelo seu comportamento. Classes

que manipulam datas podem ficar no package utils.data, enquanto que

controles personalizados podem ficar em controls ou components.

Em , temos o comando import. Este comando é usando para importar uma

classe de um determinado package. Isso tem que ser feito porque a linguagem

ActionScript não sabe onde estão todas as classes e todos os packages do seu

sistema, e ficaria lento ler todos eles quando o seu programa estivesse sendo

executado. Em estamos importando a classe Sprite do package

flash.display, para que possamos usá-lo em algum momento na nosso

programa.

A classe Sprite é uma classe bastante básica do Action Script 3, e sua

principal funcionalidade é conter uma lista de controles visuais que são

usados quando o programa é carregado. Para os usuários Flash, a classe

Sprite pode ser definida como uma classe semelhante a classe MovieClip,

mas sem o timeline (proveniente de animações do Flash).

Em , temos a definição da classe HelloWorld, que estende de Sprite.O

conceito de estender está ligado a orientação a objetos, e podemos pensar que

a classe HelloWorld possui a mesma característica da classe Sprite.

Em , temos a criação de um método chamado HelloWorld. Este método

possui o mesmo nome da classe, e por isso ele será chamado assim que a

classe HelloWorld foi criada. Chamamos esse comportamento como “método

construtor”.

Em , temos o nosso programa, que no momento usa apenas o comando

trace(). Nas explicações a seguir, sobre todos os conceitos iniciais do Action

Script, você poderá inserir o código no método construtor do Hello World,

Page 22: Dominando action script3

para analisar os resultados. Não estaremos criando projetos para cada

exemplo, mas sim adicionando os exemplos no HelloWorld.

Variáveis

Para um computador, uma variável é apenas um espaço de memória

reservado, no qual podemos adicionar algum valor. Para nós, uma variável

pode ser considerada como um lugar onde podemos guardar dados, sejam

eles dados numéricos, um texto qualquer ou outro objeto. Estes dados são

referenciados através de um nome que damos a ele, e também através do seu

tipo (se é texto ou número).

No Action Script 3.0, definimos uma variável da seguinte forma:

var nomeDaVariavel : String;

A criação de uma variável o Action Script 3.0 é determinada pela palavra

reservada var, seguido do nome da variável, e do seu tipo.

Atenção: Uma palavra reservada é uma palavra que não pode ser usada para dar nome a variáveis, classes ou métodos. Exemplos: var, if, classe etc.

Uma lista completa de palavras reservadas está neste link:

http://help.adobe.com/en_US/ActionScript/3.0_ProgrammingAS3_Flex/WS5b3ccc516d4fbf351e63e3d118a9b90204-7f9b.html#WS5b3ccc516d4fbf351e63e3d118a9b90204-7f6e

Você pode definir o nome da variável com algo relacionado ao seu contexto.

Por exemplo, se você quer armazenar o nome da pessoa, a variável

“nomeDaPessoa” é muito melhor que “x”. Pode-se perceber que a primeira

letra do nome da variável é em minúsculo, sendo que as outras letras iniciais

que compõem a palavra são em maiúsculo. Isto é apenas uma convenção que

pode ser ditada pela sua equipe ou projeto. Neste caso, estou usando a

convenção do próprio Action Script, localizado neste endereço:

http://opensource.adobe.com/wiki/display/flexsdk/Coding+Conventions

Page 23: Dominando action script3

Atenção quanto a nome de variáveis, pois nomeDaVariavel é diferente de

NomedaVariavel. Chamamos isso de Case Sensitive, isto é, letras maiúsculas

diferem de letras minúsculas.

Lembre: O nome que você vai dar a sua variável é melhor que qualquer tipo de comentário. Seja coerente e use letras maiúsculas para o início de cada palavra. Veja a diferença entre valorExtornoCliente e valorextornocliente ou vlr_ext_cli

Agora que criamos a variável, como podemos relacioná-la a um valor? Isso

pode ser feito de duas formas distintas:

var nomeCliente : String = "Daniel";

ou

var nomeCliente : String;

nomeCliente = "Daniel";

Nestes dois casos, o efeito é o mesmo. Podemos definir um valor para uma

variável logo na sua declaração, ou então definir o seu valor após a

declaração. Não precisa ser na linha imediatamente a seguir, pode ser em

qualquer lugar desde que a variável criada exista naquele contexto.

Tipos de variáveis

No exemplo anterior criamos uma variável do tipo String (texto). Existem

dezenas de tipos prontos para serem usados. Os mais importantes são: String,

int, Number, Date, Object, Array.

String

Como mencionado, o String é usado para trabalhar com textos. Na verdade, o

tipo String é uma classe String, que também possui métodos e propriedades.

Isso quer dizer que o exemplo a seguir é perfeitamente possível:

var nomeCliente : String = "Daniel";

trace(nomeCliente.charAt(0));

trace(nomeCliente.toUpperCase());

Page 24: Dominando action script3

Ou seja, quando criamos uma variável do tipo String podemos interagir com

esta variável. No Flash Builder, por exemplo, temos uma vasta lista de

métodos que podem ser usados para os mais diferentes tratamentos,

acessados através da complementação de código (ctrl+espaço):

Assim como em outras linguagens, o tipo String aceita caracteres de escape.

Um caractere de escape é formado por uma contra barra, seguida de uma

letra. No código a seguir, usamos um caractere de escape para quebrar um

texto em duas linhas:

var textoGrande : String = "O rato roeu a roupa \n do rei

de roma";

trace(textoGrande);

O resultado deste código é:

O rato roeu a roupa

do rei de roma

Veja que o \n (new line) quebrou o texto em duas partes. Outros caracteres de

escape são:

Page 25: Dominando action script3

Caractere Resultado

\b Backspace

\n New line – Nova linha, como no exemplo anterior

\t Tab

\unnnn Insere caracteres especiais no formato Unicode

\unn Insere caracteres especiais no formato Unicode

\‟ Insere ‟

\” Insere ”

\\ Insere uma barra \

O método toString()

Este método especial está presente em todas as classes do Action Script. Ele é

usado para converter qualquer tipo de objeto (lembre-se: uma data do tipo

Date é um objeto, e um número do tipo Numeric também). O método

toString é muito usado para exibir informações rápidas sobre determinados

objetos, ajudando no debug.

O exemplo a seguir imprime uma data formatada para texto, ao invés de

imprimir a data utilizando o tipo Date:

var hoje:Date = new Date();

trace(hoje);

trace(hoje.toString());

trace(hoje.toDateString());

trace(hoje.toTimeString());

Resultado:

Mon Aug 30 21:12:35 GMT-0300 2010

Mon Aug 30 21:12:35 GMT-0300 2010

Mon Aug 30 2010

21:12:35 GMT-0300

Este exemplo possui saídas idênticas no primeiro e segundo trace. Isso

acontece porque o comando trace trata internamente o objeto realizando o

Page 26: Dominando action script3

toString. Nas outras saídas, mostramos outros formatos de saída para as

variáveis que são do tipo Data.

É possível implementar o próprio toString(), em qualquer classe do Action

Script 3.0, bastando apenas criar o método e usar o operador override, veja:

package

{

import flash.display.Sprite;

public class HelloWorld extends Sprite

{

public function HelloWorld()

{

trace(this.toString());

}

public override function toString() : String

{

return "toString: " + super.toString();

}

}

}

Resultado:

toString: [object HelloWorld]

Override significa sobrescrever, então estamos sobrescrevendo o método

toString da classe HelloWorld. Veja que no método construtor chamamos o

próprio toString da classe, e ainda usamos o toString da classe Sprite através

do comando super, que chama propriedades e métodos da classe pai. Iremos

rever estes conceitos no tópico sobre orientação a objetos.

Number, int e uint

A representação de números pode ocorrer em formatos distintos. Isso

acontece porque um número pode ser negativo ou positivo, pode ter casas

decimais ou não. Para cada característica, existe um tipo diferente. O tipo

mais comum é o Number, um formato de 64 bits que aceita números

positivos e negativos, além de números fracionados.

Page 27: Dominando action script3

O tipo int possui 32 bits e aceita números positivos e negativos, mas não

aceita números fracionados, apenas números inteiros. O tipo uint aceita

apenas números inteiros e positivos. O valor máximo e mínimo de cada um

deles pode ser definido através do seguinte código:

trace(uint.MIN_VALUE); //0

trace(uint.MAX_VALUE); //4294967295

trace(int.MIN_VALUE); //-2147483648

trace(int.MAX_VALUE); //2147483647

trace(Number.MIN_VALUE); //4.9406564584124654e-324

trace(Number.MAX_VALUE); //1.79769313486231e+308

O uso de cada um destes tipos varia de acordo com a necessidade. É válido

lembrar que usar o tipo Number abrange todos os tipos numéricos, mas

perde-se em performance, pois estamos alocando um espaço desnecessário na

memória.

Quando criamos uma variável do tipo Number, e não atribuímos nenhum

valor a ela, o seu valor padrão é NaN, que significa invalido ou indefinido.

Os tipos int e uint assumem o valor 0 quando são criados.

Boolean

As variáveis booleanas podem assumir dois valores: true ou false. No

momento em que criamos uma variável booleana, ela ainda está com o valor

padrão false, e somente torna verdadeira se houver a atribuição.

var isNew : Boolean;

trace(isNew); // false

isNew = true;

trace(isNew); // true

Date

Campos do tipo Date são feitos expressamente para manipular uma data fixa,

sendo que uma data é composta do dia/mês/ano e da hora:minuto:segundo,

não necessariamente nesta seqüência. A criação de uma data pode ser feita da

seguinte forma:

Page 28: Dominando action script3

var agora:Date = new Date();

trace(agora); // Fri Sep 3 15:02:06 GMT-0300 2010

Também é possível criar datas a partir de datas existentes, como no exemplo

a seguir:

var ontem:Date = new Date("09/02/2010");

trace(ontem); // Thu Sep 2 00:00:00 GMT-0300 2010

Como pode-se ver no exemplo acima, criamos uma data no formato

americano: MM/DD/AAAA. Pode-se criar datas em outros formatos, como

no exemplo a seguir:

var data:Date = new Date("01 Sep 2009");

trace(data); // Tue Sep 1 00:00:00 GMT-0300 2009

Como também podemos ver uma data em diferentes formatos:

var hoje:Date = new Date();

trace(hoje);

trace(hoje.toString());

trace(hoje.toDateString());

trace(hoje.toTimeString());

Atenção: O formato DD/MM/AAAA é setado automaticamente através da propriedade formatString dos componentes de data do Flex.

Object

Esta classe é considerada a classe base de todas as outras classes da

hierarquia do Action Script. Pode-se criar um objeto qualquer da seguinte

forma:

var pessoa:Object = new Object();

pessoa.Nome = "Daniel";

pessoa.Telefone = 222111;

trace(pessoa); // [object Object]

trace(pessoa.Nome); // Daniel

trace(pessoa.Telefone); // 222111

O mesmo objeto criado acima poderia ser criado também da seguinte forma:

var pessoa:Object = {Nome:'Daniel',Telefone:111222}

trace(pessoa); // [object Object]

Page 29: Dominando action script3

trace(pessoa.Nome); // Daniel

trace(pessoa.Telefone); // 222111

Constantes

Uma constante é uma variável especial que define um valor que nunca é

alterado. A constante é definida pela palavra const, conforme o exemplo a

seguir:

package

{

import flash.display.Sprite;

public class HelloWorld extends Sprite

{

public const PI:Number = 3.14;

public function HelloWorld()

{

trace(PI); // 3.14

}

}

}

Usamos o PI apenas de exemplo. Você pode usar o valor de PI através da constante Math.PI

Escopo

A definição do escopo de uma variável influencia mais na legibilidade do

programa do que na memória em si. Antigamente era até notável definir o

escopo de uma variável para manter um nível de memória aceitável, mas hoje

em dia o principal propósito é definir somente uma região onde a variável

será vista.

O escopo pode ser definido como a parte do programa em que uma variável

está ativa. Geralmente a variável está ativa somente no pedaço de bloco de

código em que foi criada. Observe o código a seguir e as variáveis a,b e c.

package

Page 30: Dominando action script3

{

import flash.display.Sprite;

public class HelloWorld extends Sprite

{

protected var a:String;

public function HelloWorld()

{

var b:String;

if (true)

{

var c:String;

}

}

}

}

Em , temos a variável a que está disponível em toda a classe HelloWorld.

A variável b () está disponível somente no método construtor da classe.

Uma particularidade da linguagem Action Script é que a variável c não está

definida apenas dentro do bloco if, mas em todo o método construtor

também. Isso acontece porque o Action Script 3.0 não possui escopo a nível

de blocos, mas apenas a níveis de funções. Isso é diferente do C#, C++ e

Java.

Visibilidade

Outro conceito importante é a visibilidade de uma variável, método ou classe.

Você já deve ter percebido, por diversas vezes, a palavra “public” nas classes

e em métodos. No exemplo sobre Escopo, vimos em uma variável que ao

invés de public, é protected. Estes “modificadores” definem a visibilidade da

variável dentro da classe, ou de um método ou da própria classe. A

visibilidade determina até quanto uma variável está visível para uso em

relação a outra classe. Os modificadores do Action Script 3.0 são:

public: disponível em todo o momento. Uma classe fica disponível

para todo o sistema, assim como suas variáveis e métodos públicos.

Page 31: Dominando action script3

private: usado em variáveis dentro de uma classe. As variáveis ficam

disponíveis somente para aquela classe, e nenhuma outra.

protected: As variáveis ficam disponíveis para a classe e suas sub-

classes (herança).

internal: As classes ficam disponíveis somente no seu package.

Os modificadores acima possuem algumas incompatibilidades. Por exemplo,

não faz sentido criar uma classe protected, ou uma classe private.

Operadores

Os operadores no Action Script 3.0 são usados para os mais diversos fins.

Existe uma semelhança grande com o padrão de operadores de qualquer

linguagem baseada no ECMAScript3, como php, C#, Java. A seguir

apresentamos os operadores mais comuns.

Atribuição (=) : Basicamente é usado para atribuir um valor a uma

variável.

Soma,subtração,multiplicação, divisão (+,-,*,/): Conhecidos para

efetuar cálculos básicos em variáveis numéricas. O operador +

também pode concatenar caracteres.

Módulo (%): Usado para se obter o “resto” de uma divisão. Por

exemplo, 5/3 retorna o resto 2. Ou seja, 5%3 é igual a 2.

Potência (^) : Eleva um valor a potência de outro. Por exemplo: 5^2

significa 5 elevado a 2.

Incremento (++) e Decremento(--): Usado para somar ou subtrair

um valor de 1. Neste caso a precedência do operador define o seu

comportamento. Supondo que temos a variável i com o valor 2:

o trace(i++) : Vai retornar 2, e depois somar 1

o trace(++i): Vai somar 1, e retornar 3

Nota do autor: Poucas foram as vezes que usei ++i. Se isso gerar confusão, é melhor fazer i++ antes de usar a variável i.

Page 32: Dominando action script3

Operadores compostos ( +=, -=, *=, /=, %=): São usados para

compor as variáveis de acordo com o operador. O exemplo explica

tudo:

o x += 1 é o mesmo que x = x+1

o x -= z é o mesmo que x = x – z

o y *= 10 é o mesmo que y = y * 10

Precedência de operadores

O que fazemos quando temos o seguinte cálculo:

var i : Number = 10 + 5 - 3 * 2;

Ou seja, o valor 10 será somado ao 5, que será subtraído por 3, ou por 6? Ou

então 10 será somado com 4? As possibilidades são muitas e neste caso existe

uma procedência em relação aos operadores. Esta procedência diz que

operadores de multiplicação e divisão são calculados antes dos operadores de

soma e multiplicação. Então teremos algo: 10+5-6 = 9.

Dica: Não confie na precedência de operadores. Defina parêntesis, sempre!

Os parêntesis são usados para forçar a precedência. É recomendável sempre

usar parêntesis para separar claramente uma operação de cálculo complexa.

Exemplo:

var i : Number = 10 + 5 - 3 * 2 / 7 * 9 - 5 ^ 2;

var j : Number = ( (10 + 5 - 3 * 2) / (7 * 9 - 5) )^2 ;

Condicionais

Uma condicional é uma estrutura de desvio de código, usada amplamente em

qualquer programa de computador. Uma condição é formada por uma

expressão que pode retornar falso ou verdadeiro. Dependendo do resultado, o

fluxo de código dentro do programa será alterado.

As condições são feitas através de operadores, sendo os mais utilizados

apresentados a seguir

Page 33: Dominando action script3

Igualdade ( == ): Usado para comparar um valor com o outro.

Cuidado com a diferença entre igualdade e atribuição

Desigualdade ( != ): O sinal de interrogação indica negação, sendo

que != indica “é diferente de”.

Maior, menor, maior ou igual, menor ou igual: Caracterizado pelos

símbolos >, <,>=,<=. Indicam, por exemplo, se um valor é maior que

o outro.

Pode-se unir diversas condições através dos operadores AND (&&) e OR (||).

Por exemplo, idade > 10 && idade <= 20, indica uma faixa de 11 a 20.

Como já foi dito, uma condição sempre retorna verdadeiro ou falso. Mas

existem tipos especiais que, dependendo de seu valor, são convertidos

automaticamente para verdadeiro/falso. Por exemplo, quando temos um

objeto qualquer e usamos ele para uma condição, esta resultará em verdadeiro

se este objeto não for nulo. Quando testamos números inteiros temos um

comportamento semelhante. Se o número for diferente de zero, a expressão

será convertida em verdadeiro, caso contrário, falso. Para strings, uma

condição será falsa somente se a string estiver vazia. Veremos melhor as

condições após o entendimento do if.

if

A condicional mais famosa existente é o if (em português: se). Esta condição

executa o seu bloco de código se a expressão avaliada retorna verdadeiro. O

exemplo a seguir ilustra este processo:

var idade:uint = 25;

if (idade>18)

{

trace("Você é maior de idade");

}

if (idade<18)

{

trace("Você é menor de idade");

}

Page 34: Dominando action script3

Neste código, definimos a variável idade com o valor 25. O primeiro if avalia

se idade é maior que 18. Se for, o fluxo de código entra em . No segundo if,

quando avaliamos se idade é menor que 18, o código em não será

executado, pois a condição idade<18 retorna falso.

Em relação a condições especiais, podemos citar objetos, números e texto. O

exemplo a seguir ilustra melhor estas condições:

//Objetos:

var obj:Object = {Nome:"Daniel"}

if (obj)

trace("obj não é nulo");

//Numeros

var idade:uint = 0;

if (idade)

{

if (idade<18)

{

}

//....... continua

}

else

trace("você ainda não nasceu");

//String

var str:String = "";

if (str)

trace(str)

else

trace("preencha algo para str");

Atenção: Neste exemplo podemos perceber ifs sem o uso de chaves. Isso somente é possível quando o bloco dentro do if contiver uma única linha. Se forem duas ou mais, o uso do parêntesis é obrigatório.

Page 35: Dominando action script3

Atenção 2: Em concursos públicos/provas de programação, o uso de ifs sem chave e identado é uma pegadinha que você se confudir, então tome cuidado: if (condição) faça A faça B faça C

Neste if, o bloco B e C serão executados independentemente da condição. Cuidado!!

if + else

O código anterior usou dois ifs que poderiam ser substituídos pelo if/else

(se/então). O else é usado para executar o bloco de código quando a condição

do if for falsa. O exemplo anterior pode ser resumido a:

if (idade>18)

{

trace("Você é maior de idade");

}

else

{

trace("Você é menor de idade");

}

If + elseif + else

Pode-se testar várias condições através do elseif, como no exemplo a seguir:

var idade:uint = 50;

if (idade < 18)

{

trace("Você é menor de idade");

}

else if (idade < 60)

{

trace("Você é maior de idade");

}

else if (idade < 150)

{

trace("Você é idoso");

}

Page 36: Dominando action script3

else

trace("Você está morto!");

Este exemplo, um pouco mais extenso, mostra algumas particularidades do

if/elseif/else. Inicialmente pode-se perceber que o bloco de cada if é

executado apenas uma vez. Vou explicar melhor, quando temos idade igual a

50, o primeiro if falha e caímos então no primeiro else if, cuja a condição é

idade<60. Este bloco será executado, e somente ele. O próximo if possui a

condição idade<120, que também satisfaz quando idade=50, mas como o

bloco já foi executado no if anterior, este if nem será avaliado. Em outras

palavras, quando temos um bloco com vários elseif, somente um será

executado. No final do código temos o else que será executado se nenhuma

condição de todos os else ifs for aceita. No exemplo, o else será executado se

a idade for maior ou igual a 150.

Quanto o uso de else/if torna-se algo extremamente extenso, podemos usar

outra condição para facilitar o entendimento do código. Esta condição se

chama switch.

Switch

O switch é usado basicamente para testar diversos valores, facilitando a

leitura em relação ao else if. O exemplo a seguir ilustra este processo:

var hoje:Date = new Date();

var dia:Number = hoje.day; //dia da semana

switch (dia)

{

case 0:

trace("domingo");

break;

case 1:

trace("segunda");

break;

case 2:

trace("terça");

break;

Page 37: Dominando action script3

case 3:

trace("quarta");

break;

case 4:

trace("quinta");

break;

case 5:

trace("sexta");

break;

case 6:

trace("sábado");

break;

}

A sintaxe do switch é formada pelo uso do case, seguido de um valor, e o uso

do break, para que quando o valor especificado for encontrado, o bloco do

case seja executado e ao encontrar o break, seja finalizado.

Pode-se usar vários cases com o mesmo bloco de código, por exemplo:

var hoje:Date = new Date();

var dia:Number = hoje.day; //dia da semana

switch (dia)

{

case 0:

case 6:

trace("descançar!!");

break;

case 1:

case 2:

case 3:

case 4:

case 5:

case 6:

trace("trabalhar!!");

break;

}

O código acima é perfeitamente válido. Também podemos obter um resultado

semelhante com a condição default. Veja:

switch (dia)

Page 38: Dominando action script3

{

case 0:

case 6:

trace("descançar!!");

break;

default:

trace("trabalhar!!");

break;

}

O bloco da condição default é executado somente quando todos os cases não

satisfazerem a condição proposta.

Operador ternário (ou condicional)

Este operador foi criado especialmente para verificações rápidas onde

escrever um bloco if é muito custoso. O seu uso está atribuído ao caractere ?

(interrogação) e ao : (dois pontos), formando a seguinte sintaxe:

(condição) ? “verdadeiro” : “falso”

Nesta sintaxe, temos inicialmente a condição, que será testada e caso seja

verdadeira, o primeiro mini bloco (antes dos :) será executado. Se a condição

for falsa, o segundo mini bloco (após os :) será executado. O exemplo a

seguir ilustra este processo:

(dia==0||dia==6) ? trace ("descançar") : trace

("trabalhar");

//ou:

trace( (dia==0||dia==6) ? "descançar" : "trabalhar");

Pode-se usar o operador ternário para atribuições, como no exemplo anterior,

onde o resultado seria a entrada do parâmetro do comando trace().

A seguir outro exemplo perfeitamente válido:

var info:String;

info = (dia==0||dia==6) ? "descançar" : "trabalhar";

trace(info);

Atenção: O operador ternário deve ser usado com cautela, somente para expressões extremamente simples.

Page 39: Dominando action script3

Loops

Um loop é uma forma de percorrer um determinado código várias vezes. As

formas de se criar um loop cresceram de acordo com o avanço das linguagens

de programação, sendo as mais conhecidas o for e o while.

for

O for é a forma mais conhecida para criar um loop, definido-se um intervalo

de valores que condizem com a quantidade de vezes que você quer executar o

bloco do código. O loop for possui a seguinte estrutura:

for (var i:int = 0;i<100;i++)

{

//fazer algo

}

Veja que o for possui três parâmetros, separados por “;” - que definem a

quantidades de vezes que o loop será realizado. O primeiro parâmetro cria

uma variável chamada de i (geralmente usamos as letras i,j,k para loops) que

é do tipo int e possui o valor inicial igual a 0.

O segundo parâmetro do for atribui uma condição que mantém o loop

funcionando. Enquanto a condição estiver sendo satisfeita, o loop continuará

rodando. O terceiro parâmetro indica o incremento da variável i, neste caso a

cada finalização do bloco do for, a variável será incrementada em uma

unidade.

Pode-se usar o for para a interação em um Array:

var arr:Array = ["um","dois","tres"];

for (var i:int = 0;i<arr.length;i++)

trace(arr[i]);

Neste exemplo, veja que a condição do laço está dependente do número de

itens do array (), e que conseguimos obter o item atual utilizando a

variável i ().

Page 40: Dominando action script3

for each ... in

O último exemplo era muito utilizado em linguagens mais antigas. A única

forma de percorrer um array era através do loop for. Felizmente, com o

avanço das linguagens de programação, o uso do for each (para cada) tornou-

se uma forma mais simples de percorrer um Array. Veja o mesmo exemplo

anterior, agora com for each:

var arr:Array = ["um","dois","tres"];

for each (var item:String in arr)

trace(item);

Veja que o for each interage através de cada item do array, atribuindo a cada

laço o valor na variável item. Use o for each sempre quando for trabalhar

com dados provenientes de um Array ou de um XMLList, pois é mais fácil

de entender e codificar.

Dica: Se for fazer um for each com um objeto que é ArrayList ou ArrayCollection, use o atributo source ao invés de usar o próprio ArrayList. Veja um exemplo: var arr:ArrayList = new ArrayList(["um","dois","tres"]);

for each (var item:String in arr.source)

trace(item);

while

O loop while é usado sempre quando não conhecemos ao certo a quantidade

de vezes que o bloco de código será repetido. Por exemplo, podemos usar o

while para remover uma quantidade de itens de um array. Isso não seria

possível com o for porque a quantidade de itens está sempre mudando, pois

quando retiramos um item do array, a sua propriedade length é alterada.

Por exemplo:

var arr:Array = ["um","dois","tres"];

Page 41: Dominando action script3

while (arr.length>0)

{

trace(arr[arr.length-1] + " será excluido");

arr.pop();

}

trace("arr nao possui mais items!");

Neste exemplo, o while faz o loop do código enquanto houver itens no array.

Veja que, se a condição inicial do while não for satisfeita, o bloco de código

do while não será executado.

do ... while

O loop do ... while tem a particularidade de executar o bloco de código do

while pelo menos uma vez. Isso acontece porque a condição somente é

testada no final do loop. O exemplo a seguir ilustra este processo:

var num:int = 10;

do

{

num++;

}while (num < 10)

trace(num); // 11

Pulando ou saindo do loop

Existem dois comandos: continue e break que são responsáveis em,

respectivamente, pular o loop ou então sair do loop. Eles são úteis quando

queremos verificar, por exemplo, se o loop não está entrando em laço

infinito, ou se devemos necessariamente pular para o próximo item. Por

exemplo, suponha que você tenha um array de números, e que precise fazer

um processamento muito grande nelas, dentro de um loop. Mas no código só

há interesse em números pares, e você não quer realizar o processamento em

números ímpares. O código a seguir ilustra o problema:

var arr:Array = [1,2,3,4,5,6,7,8,9]

for each (var numero:int in arr)

Page 42: Dominando action script3

{

if (numero%2 != 0) continue;

trace("Fazendo calculo para: " + numero);

}

Neste código usamos o módulo de 2 para sabermos se o número é impar. Se

for, a instrução continue é chamada e o processamento “pula” para o próximo

item. O resultado deste código é:

Fazendo calculo para: 2

Fazendo calculo para: 4

Fazendo calculo para: 6

Fazendo calculo para: 8

Veja que usamos um if com o seu código na mesma linha, e é claro que o

código a seguir também funciona:

if (numero%2 != 0)

{

continue;

}

Mas fica feio pra caramba!! (nota do autor)

O break é usado para pular completamente o loop, indo para a próxima linha

após o loop. Suponha que o número 0 é uma instrução para parar

completamente o processamento:

var arr:Array = [1,2,3,4,5,6,0,8,9]

for each (var numero:int in arr)

{

trace("Analisando: " + numero);

if (numero == 0)

{

trace("defeito na máquina de leitura. programa

abortado");

break;

}

if (numero%2 != 0) continue;

trace("Fazendo calculo para: " + numero);

}

O resultado deste programa é:

Page 43: Dominando action script3

Analisando: 1

Analisando: 2

Fazendo calculo para: 2

Analisando: 3

Analisando: 4

Fazendo calculo para: 4

Analisando: 5

Analisando: 6

Fazendo calculo para: 6

Analisando: 0

defeito na máquina de leitura. programa abortado

Funções

As funções foram criadas ainda na época da linguagem estruturada e tinham a

principal finalidade de reutilizar partes do código que eram executadas mais

de uma vez. Com o passar do tempo, as funções ficaram cada vez mais

importantes e passaram também a separar melhor o código da aplicação, de

forma que tornasse mais legível.

Basicamente, uma função em Action Script 3.0 possui a seguinte sintaxe:

public function fazAlgumaCoisa(a:String):Boolean

{

return true;

}

Analisando a sintaxe, temos inicialmente a definição da Visibilidade da

função. Ela pode ser public, protected, private ou internal. Depois temos a

palavra reservada function seguido do nome da função. Após o nome da

função, temos a definição dos parâmetros de entrada, o nome da variável e do

seu tipo. Pode-se criar quantos parâmetros forem necessários. No final da

criação da função temos a definição do tipo de retorno que a função assume.

Neste caso, a função retorna algo booleano. Quando a função não for retornar

nada, inserimos void:

public function fazAlgumaCoisa(a:String):void

{

//não retorna nada....

}

Page 44: Dominando action script3

Função ou método?

Existe uma separação conceitual em função e método. Uma função é criada

fora do escopo de uma classe. Um método nada mais é que uma função

dentro de uma classe. Você vai perceber que quando formos abordar o

conceito de orientação a objetos, a palavra função será substituída por

método, mas a sintaxe é a mesma.

Parâmetros

Os parâmetros passados para a função são globais dentro da função como um

todo. Você pode usá-los e modificá-los, mas precisa tomar cuidado quando

modificar seus valores, pois eles podem não ser refletidos em toda a sua

classe.

Explicando melhor, tomamos o exemplo a seguir:

public function HelloWorld()

{

var raio : int = 10;

alteraRaio(raio);

trace(raio); // 10

}

public function alterarRaio(raio:int) : void

{

raio = raio + 5;

}

A saída do comando trace() é 10, e não 15. Isso acontece porque quando

chamamos o método alterarRaio() passamos a variável raio por valor.

Quando passamos algo por valor, estamos clonando a variável e apenas

repassando o seu valor. Ou seja, o conteúdo na memória é duplicado e a

variável original não altera o valor. Isso sempre acontece com variáveis do

tipo primitivos String, Number, int, uint e Boolean.

Agora vamos a um novo exemplo, passando um objeto ao invés de um tipo

primitivo:

public function HelloWorld()

Page 45: Dominando action script3

{

var circulo : Object = {Raio:10};

alteraRaio(circulo);

trace(circulo.Raio); // 15

}

public function alteraRaio(circulo:Object) : void

{

circulo.Raio = circulo.Raio + 5;

}

Agora criamos um objeto chamado circulo que possui a propriedade Raio.

Quando passamos este objeto como parâmetro da função alteraRaio(),

estamos passando esse parâmetro por referência. Isso significa que a

referência do objeto (o ponteiro que aponta para o endereço de memória do

objeto) é repassada, e que ao alterar as propriedades desse objeto, as

alterações serão mantidas. Chamamos esta passagem de “passagem por

referência”, e isso sempre acontece quando repassamos um objeto por

parâmetro de uma função.

Parâmetros rest (...)

Existe uma particularidade na criação de parâmetros chamada “rest”, que

indica uma série de parâmetros que são automaticamente transformados em

um array de dados.

A idéia básica do rest é possibilitar que o usuário possa adicionar quantos

parâmetros forem necessários. Por exemplo, suponha que você deseja criar

uma função chamada “média”, e deseja fazer com que o usuário possa

chamar a função da seguinte forma:

Media(10,5);

Media(1,2,3,4);

Media(10,10,10,10,10,10);

Pode-se ver que a quantidade de parâmetros é dinâmica. Isso é feito com o

uso do parâmetro rest, representado por três pontos, veja:

public function HelloWorld()

{

trace(Media(10,2)); // 6

Page 46: Dominando action script3

trace(Media(1,1,1,1,1,1,1,1,1)); // 1

trace(Media(1,2,3,4,5)); // 3

}

public function Media(... numeros:Array) : Number

{

var total:Number=0;

for each (var item:Number in numeros)

total += item;

return total/numeros.length;

}

Neste exemplo, o uso dos três pontos em indica que os parâmetros

passados são armazenados em um array chamado números.

Argumento padrão

No Action Script 3.0 pode-se passar um argumento padrão para cada

argumento de uma função. Os argumentos podem ter valores padrão através

do sinal de atribuição igual, veja:

public function HelloWorld()

{

SayHello("Daniel"); // Olá Daniel

SayHello(); // Olá Anônimo

}

public function SayHello(nome:String="Anônimo") : void

{

trace("Olá " + nome);

}

Pode-se criar quantos argumentos padrão forem necessário, mas para que

possamos omiti-lo da função, eles precisam estar sempre nos últimos

parâmetros. Ou seja, os parâmetros opcionais devem estar sempre após os

parâmetros obrigatórios. O exemplo a seguir provoca um erro de compilação:

public function Say(nome:String="eu",cid:String) : void

O correto seria:

Page 47: Dominando action script3

public function Say(cid:String, nome:String="eu") : void

Função anônima

Uma função anônima é aquela que não tem nome (óbvio!!). Ela é declarada

implicitamente no código e geralmente está atrelada a algum evento. A

criação de uma função anônima é feita da seguinte forma:

package

{

import flash.display.Sprite;

import flash.events.Event;

import flash.events.MouseEvent;

public class HelloWorld extends Sprite

{

public function HelloWorld()

{

this.stage.addEventListener(Event.ADDED, function(event:Event):void

{

trace("função anônima chamada");

}

);

}

}

}

Neste código, criamos uma função anônima como um parâmetro de uma

outra função (addEventListener). Isso é perfeitamente possível no Action

Script 3.0 (e em algumas linguagens como o JavaScript). Repare o destaque

dos parêntesis em vermelho, indicando que a função realmente é um

parâmetro.

Existem algumas diferenças das funções declaradas e das funções anônimas.

As anônimas existem somente no escopo que foram definidas, não podem ser

reutilizadas (até um certo, podem – mas dentro do escopo).

Talvez você esteja se perguntando qual a melhor, a resposta é depende do que

você quer fazer. As funções anônimas são muito usadas nos eventos

Page 48: Dominando action script3

associados a algum componente do Action Script 3.0, quando estes eventos

não precisam usar métodos reusáveis.

Nos métodos anônimos, cuidado com o uso do this, pois ao invés dele

“apontar” para o objeto da classe em que foi chamado, ele aponta para a

própria função. Veja no código a seguir as saídas do comando trace:

package

{

import flash.display.Sprite;

import flash.events.Event;

import flash.events.MouseEvent;

public class HelloWorld extends Sprite

{

protected var teste:String = "blablabla";

public function HelloWorld()

{

trace("1 " + this.toString());

trace("2 " + teste);

this.stage.addEventListener(Event.ADDED,

function(event:Event):void

{

trace("3 " + this.toString());

trace("4 " + teste);

trace("5 " + this.teste);

});

}

}

}

Saída:

1 [object HelloWorld]

2 blablabla

3 [object global]

4 blablabla

5 undefined

Veja que o item 5 do trace retorna indefinido, pois o this não refere-se a

classe HelloWolrd e sim a função anônima. Veja que, para acessar a classe,

Page 49: Dominando action script3

você deve omitir o uso do this. Este é um pequeno detalhe de escopo que

deve ser lembrando quando criarmos funções anônimas.

Funções recursivas

As funções recursivas são aquelas que chamam a si próprias. O exemplo

típico deste tipo de função é o cálculo do fatorial de um número:

public function HelloWorld()

{

trace(fatorial(5));

}

public function fatorial(num:int):int

{

trace("fat de: " + num);

if (num==0)

return 1;

else

return (num * fatorial(num-1) );

}

O resultado deste código é:

fat de: 5

fat de: 4

fat de: 3

fat de: 2

fat de: 1

fat de: 0

120

Try...catch...finally e throw

O uso do try...catch é comum na maioria das linguagens de programação e se

bem empregado pode trazer uma melhoria significativa no código. Use-o

sempre quando for realizar alguma operação que possa resultar em um erro

provável, como a leitura de um arquivo XML, ou salvar/converter alguma

imagem.

Page 50: Dominando action script3

O throw é usado justamente para disparar um erro, e pode ser usado em

conjunto com o try. Por exemplo, quando executamos este código:

package

{

import flash.display.Sprite;

import flash.events.Event;

import flash.events.MouseEvent;

public class HelloWorld extends Sprite

{

public function HelloWorld()

{

throw new Error("Disparei um erro");

}

}

}

Ao executarmos este código, temos a seguinte saída:

A janela do “Adobe Flash Player 10” aparece porque quando você instalou o

Flash Builer 4, o assistente instalou ao Flash Player na versão debug. Para

pessoas “normais” – digo, “não desenvolvedores”, que instalam o Flash

Player na versão normal, esta janela não será exibida. Aliás, não será exibido

nada, pois a política da Adobe é não incomodar o usuário “leigo” com janelas

de erro.

Page 51: Dominando action script3

Action Script 3.0 e Orientação a Objetos

A programação orientada a objetos é uma gradativa substituição da

programação estruturada. Ela ganhou força a partir de 1990, mas já era

abordada desde 1960. Atualmente a maioria das linguagens de programação

são OO (OO – orientada a objetos) .

Entendendo OO

A principal proposta da linguagem orientada a objetos é modelar o mundo

real. No mundo real temos uma infinidade de exemplos de objetos

interagindo entre si. Podemos considerar um carro como um objeto, que

possui propriedades físicas como peso, largura e altura, consumo de

combustível, etc. Também podemos considerar ações tais como acelerar,

frear e buzinar. Além destas duas características, temos também os eventos

que o carro produz. Por exemplo, se o nível de combustível estiver baixo,

emitir um sinal, ou então, se a força aplicada sobre os freios for muito forte

ao ponto derrapagem, aliviar a força nos freios.

Resumindo, um objeto no mundo tem propriedades físicas, tem ações e eventos.

Além disso, um objeto no mundo real interage com outro objeto. Por

exemplo, o objeto carro possui o objeto motor. Uma ação do objeto carro

(acelerar) pode desencadear uma série de ações do objeto motor, como

aumentar a combustão e dessa forma interferir em uma propriedade do carro,

como a velocidade. Ou seja, está tudo interligado e se no mundo real tudo

funciona bem, porque não aplicar isso na programação?

Page 52: Dominando action script3

Desta forma a OO copia estes conceitos e tenta aplicá-los na programação.

Então um objeto que possui ações, na verdade são métodos. Propriedades

físicas são como variáveis globais, sem falar dos eventos e dos

relacionamentos existentes.

Assim, quando pensamos em OO em um nível básico, estamos criando

classes (que formarão o objeto), métodos, variáveis e eventos. Assim como

no mundo real, onde cada objeto possui o seu segmento (você não vai no

açougue comprar um carro, vai?), no mundo OO temos também pacotes ou

packages, onde podemos dividir grupos de classes com funcionalidades

comuns.

Além do básico, a OO possui outros conceitos tais como interfaces, herança e

sobrecarga de métodos. Todos eles serão comentados neste capítulo. Além

disso, (mais??) existem os padrões de projeto que usam vários conceitos

relativos a OO, para uma melhor estruturação do projeto.

Alguns conceitos devem estar bem esclarecidos para quem está começando a

trabalhar com OO, e iremos numerá-los a seguir:

Objeto: Um objeto é algo “vivo” dentro do seu programa, é algo que

você pode manipular suas propriedades e métodos. No mundo real,

um objeto é o carro construído e funcionando normalmente. Ou seja,

assim como você tem vários carros em uma cidade, você pode ter

vários objetos do tipo carro em seu programa.

Classe: Uma classe é o esqueleto do objeto. É o que define como as

propriedades e métodos vão se comportar. No mundo real, uma classe

é o projeto do carro ainda na prancheta, mostrando todo o seu

funcionamento em teoria.

Instância: Um objeto é a instância de uma classe. Quando

instanciamos uma classe, estamos criando o objeto e funciona como

se estivéssemos pegando todos os dados do carro na prancheta e

criando o carro fisicamente.

Page 53: Dominando action script3

Tipo: Não existe somente um carro no mundo. Existem milhares de

tipos de carros. Uns são esportivos, outros econômicos e outros de

corrida. Um tipo de objeto é comumente chamado de classe. Ou seja,

se temos um objeto cuja classe é “Carro”, chamamos o tipo deste

objeto de “Carro”.

Baseado nestes conceitos, podemos olhar novamente a classe HelloWorld,

criada no início desta obra:

package

{

import flash.display.Sprite;

public class HelloWorld extends Sprite

{

public function HelloWorld()

{

trace("Hello World");

}

}

}

A classe HelloWorld define o tipo “HelloWorld”. Quando o programa for

executado, a classe HelloWorld será instanciada, tornando-se um objeto, e

será anexada ao programa. A definição formal de uma classe será vista no

próximo capítulo.

Um dos conceitos importantes sobre OO é a herança. Ou seja, podemos criar

uma classe com um determinado comportamento e criar uma outra classe que

possui um comportamento semelhante, mas existem diferenças em sua

totaliadade. Por exemplo, a classe Pessoa é a classe pai da classe Aluno e da

classe Professor. No exemplo HelloWorld, a classe herda da classe Sprite,

que representa uma classe do Action Script 3.0, então a classe HelloWorld,

mesmo vazia, já possui diversas variáveis e métodos.

Page 54: Dominando action script3

Classe

A definição formal de uma classe no Action Script 3.0 é a seguinte:

public class HelloWorld

Geralmente cada classe no projeto pode ser representada por um arquivo.

Você não precisa conhecer profundamente como criar uma classe da forma

correta porque o próprio Flash Builder te ajuda nisso.

Lembre-se: Você está usando o Flash Builder, use-o para criar as classes que precisa

Então para criar uma classe no nosso projeto HelloWorld, vamos até File,

New, ActionScript Class. O assistente surge conforme a figura a seguir, na

qual iremos criar a classe Carro, que será definida no package veiculos.

Assim que criamos a classe, temos no Flash Builder a seguinte configuração:

Page 55: Dominando action script3

Podemos perceber, no Package Explorer, o package veiculos seguido da

classe Carro. O código, no lado direito, é um pouco diferente da classe

HelloWorld, pois agora não existe herança.

Atenção: Não há sentido em criar a classe carro herdando de Sprite, porque carro não tem absolutamente nada a ver com visualização do programa no navegador.

Uma propriedade comum a qualquer carro é a sua cor. Então podemos criar

uma variável global chamada cor, alterando o código da classe para:

Page 56: Dominando action script3

package veiculos

{

public class Carro

{

public var cor:String;

public function Carro()

{

}

}

}

Agora para demonstrar o conceito de herança, vamos criar o carro Ferrari no

package esportivos. Novamente, usando o assistente do Flash Builder, temos:

Um detalhe agora é o campo SuperClasse, na qual definimos a classe Carro

como a classe pai de Ferrari. Você vai reparar que quando começamos a

digitar Carro, surge um popup com sugestões das classes que você tem

disponível.

Page 57: Dominando action script3

Após criar a classe, temos:

Veja no Package Explorer que a classe Ferrari está no package esportivos, e

no código temos a definição da classe com o uso do extends para definir uma

herança. Bom, se existe a herança, a variável Cor tem que estar presente na

classe Ferrari, e podemos alterar o nosso código para:

package veiculos.esportivos

{

import veiculos.Carro;

public class Ferrari extends Carro

{

Page 58: Dominando action script3

public function Ferrari()

{

cor = "Vermelho";

super();

}

}

}

Ok, existem Ferraris de outras cores, mas vamos apenas entender o conceito de hernaça.

Veja no construtor da classe Ferrari que temos a palavra super() (), que

chama o construtor da classe Carro. Esta é uma particularidade do Action

Script 3.0, usado sempre quando você quer chamar o construtor da classe pai.

Para finalizar o conceito sobre classes e herança, vamos voltar a classe

HelloWorld e instanciar a classe Ferrari, veja:

package

{

import flash.display.Sprite;

import veiculos.esportivos.Ferrari;

public class HelloWorld extends Sprite

{

public function HelloWorld()

{

var meuCarro:Ferrari = new Ferrari();

trace("O meu carro tem a cor: " +

meuCarro.cor);

}

}

}

Propriedades get/set

O conceito de propriedade vai um pouco além do conceito de variável. No

exemplo anterior, criamos uma variável pública chamada “cor”. Até este

momento era aceitável isso, mas suponha que você deseja que somente as

classes filhas de Carro pudessem alterar a sua cor. Como resolver isso?

Relembrando o tópico sobre visibilidade, podemos alterar a visibilidade da

variável cor para protected. É uma ótima saída, mas gera um efeito colateral.

Page 59: Dominando action script3

Como podemos exibir a cor do carro se a classe HelloWorld não pode mais

acessá-la? Neste problema podemos criar um método chamado GetCor(), que

retorna a cor do carro. Então temos as seguintes modificações:

package veiculos

{

public class Carro

{

protected var cor:String;

public function Carro()

{

}

public function GetCor():String

{

return cor;

}

}

}

e:

package

{

import flash.display.Sprite;

import veiculos.esportivos.Ferrari;

public class HelloWorld extends Sprite

{

public function HelloWorld()

{

var meuCarro:Ferrari = new Ferrari();

trace("O meu carro tem a cor: " +

meuCarro.GetCor());

}

}

}

Esta solução funciona, e funcionou por muito tempo na programação até os

programadores perceberem que estavam criando centenas de

getAlgumaCoisa, deixando o código sujo.

Page 60: Dominando action script3

Dica: porque esconder a variável cor? Este exemplo é apenas um exemplo, claro. Mas bons programadores sabem que quanto menos variáveis estiverem disponíveis em suas classes, melhor. Isso ajuda na manutenção futura e na prevenção de erros. Quer ver um exemplo no mundo real? Suponha que você pudesse alterar a taxa de combustão do motor na hora que bem entendesse. Melhorar a performance do carro seria uma possibilidade bem remota então resta a conclusão que provavelmente você irá emitir mais poluentes e danificar o motor.

Como solução do problema de esconder as variáveis do mundo externo e de

diminuir a quantidade de getAlgumaCoisa no seu código, o uso de

propriedades get/set passou a tornar-se uma boa alternativa, resultando em

um código mais limpo e fácil de entender.

Sempre chamamos de propriedade, uma variável que possui get e set.

A sintaxe básica para esse propriedade é:

private var _cor:String;

public function get Cor():String

{

return _cor;

}

public function set Cor(value:String):void

{

_cor = value;

}

A sintaxe básica é essa. Criamos uma variável private chamada _cor. O uso

do underscore é apenas uma forma de dizer que aquela variável “segura” um

get/set.

Depois criamos dois métodos. Repare que estes métodos têm as palavras get

e set, antes do nome da propriedade. O conteúdo destes métodos manipula

internamente a variável _cor.

Para resolver o problema proposto, em que somente as classes filhas

poderiam alterar a cor do carro, mas todas as outras poderiam acessar a

propriedade, alteramos a visibilidade do get para private, e deixamos a

variável _cor como protected.

Page 61: Dominando action script3

Você pode usar o Flash Builder para criar a propriedade automaticamente

para você. Por exemplo, ao criar a variável _cor, com ela selecionada, acesse

o menu de contexto (botão direito do mouse) e navegue até Source, Generate

Getter/Setter.

Métodos e sobrecarga (override)

Métodos criados em uma classe podem ser sobrecarregados, ou seja, podem

ser redefinidos pelas classes filhas. Por exemplo, suponha que exista um

cálculo que determina o valor de um carro. Suponha que o padrão é uma

constante vezes a quantidade de rodas, então teríamos:

package veiculos

{

public class Carro

{

public function Carro()

{

_rodas = 4;

}

protected var _cor:String;

public function get Cor():String

{

return _cor;

}

protected var _rodas:uint;

public function get Rodas():uint

{

return _rodas;

}

public function obterPreco():uint

{

return Rodas*10000;

}

}

}

e:

package veiculos.esportivos

{

import veiculos.Carro;

Page 62: Dominando action script3

public class Ferrari extends Carro

{

public function Ferrari()

{

_cor = "Vermelho";

super();

}

override public function obterPreco():uint

{

return 50*super.obterPreco();

}

}

}

O uso da palavra override indica que o método está se sobrepondo ao método

do pai. Podemos inclusive acessar o método do pai através do uso da palavra

super seguido do método desejado.

O código de HelloWorld fica desta forma:

package

{

import flash.display.Sprite;

import veiculos.esportivos.Ferrari;

public class HelloWorld extends Sprite

{

public function HelloWorld()

{

var meuCarro:Ferrari = new Ferrari();

trace("O meu carro tem a cor: " +

meuCarro.Cor);

trace("O preço é: " +

meuCarro.obterPreco());

}

}

}

A saída é:

O meu carro tem a cor: Vermelho

O preço é: 2000000

Page 63: Dominando action script3

Métodos e variáveis estáticos

Um método estático é um tipo especial de método que não necessita que a

classe esteja instanciada para que seja usada. Por exemplo, a classe Math,

usada para cálculos matemáticos, não necessita necessariamente que seja

instanciada para que seus métodos sejam usados. Veja:

trace(Math.sin(30));

Os métodos estáticos são chamados diretamente pela classe. Para criar um

método estático, usamos a palavra chave static. Por exemplo:

package veiculos.esportivos

{

import veiculos.Carro;

public class Ferrari extends Carro

{

//......

public static function Buzinar():String

{

return "foooom";

}

}

}

e:

trace(Ferrari.Buzinar());

O mesmo pode ser usado, por exemplo, com uma constante:

public static const BUZINA:String = "Foom";

e:

trace(Ferrari.BUZINA);

Constantes estáticas são muito usadas em eventos, que serão vistos mais

adiante.

Page 64: Dominando action script3

Interfaces

Existem dois estágios de entendimento sobre interfaces: Ou você adora elas,

e as usa em seu s programas, ou você nunca entendeu direito o seu propósito

e nem usa. Ok, podem existir outros estágios, mas provavelmente você já

passou pelo menos por algum dos dois primeiros comentados.

Uma interface funciona como um contrato no mundo real. Um contrato no

mundo real diz que as obrigações que tem que cumprir, como por exemplo

um contrato de emprego, dizendo que você tem que desenvolver software e

não pode ficar de papo no MSN. Assim, uma interface diz a uma classe o que

ela deve fazer, e nada mais.

As interfaces são úteis também quando queremos definir um comportamento

comum entre diversas classes existentes, mas estas classes não possuem um

ancestral.

Voltando ao nosso exemplo de carros, suponha que agora estamos criando

um programa para seguradoras e que nesse meio temos carros, lanchas e

helicópteros. Também temos casas e temos seguros relativos a pessoas.

Como programador, você logo pensa: ok, não dá pra criar uma classe pai para

todo mundo, pois os objetos possuem comportamentos completamente

diferentes, mas mesmo assim todos eles possuem uma taxa de juros em caso

de atraso no pagamento, então como eu posso resolver esse problema de

forma a não prejudicar a legibilidade do meu código?

A resposta é com o uso de interfaces, ou seja, como todas as classes distintas

(e que não possuem a mesma classe Base) possuem comportamentos que

podem ser padronizados, o uso de interface pode ser empregado.

Como criar uma interface

Com o Flash Builder, navegue até File, New, ActionScript Interface. Crie a

interface ITaxa no package taxas. Neste momento temos o seguinte código:

Page 65: Dominando action script3

Para criamos um método que será comum a todas as classes que

implementarem ITaxa, adicionamos o seguinte código:

package taxas

{

public interface ITaxa

{

function getVariacaoTaxa():Number;

}

Page 66: Dominando action script3

Ou seja, criamos o método getVariacaoTaxa(), mas não implementamos

nada. A interface nunca implementa nada, apenas diz quais são os métodos e

propriedades que devem ser implementados.

Como associar uma interface a uma classe

Agora vamos aplicar esta interface na classe Carro. O código fica:

package veiculos

{

import taxas.ITaxa;

public class Carro implements ITaxa

{

//............

public function getVariacaoTaxa():Number

{

return 0.02;

}

}

}

O uso do implements diz que a classe implementa uma interface. Então, se a

classe implementa ITaxa, ela deve declarar e implementar o método

getVariacaoTaxa.

Agora supondo a classe Pessoa, que não tem nada a ver com Carro,

implementando a mesma interface:

Page 67: Dominando action script3

Veja que ao criar a classe Pessoa, podemos adicionar a interface a ser usada,

fazendo com que o método seja criado automaticamente. O código gerado

pelo Flash Builder é o seguinte:

package pessoas

{

import taxas.ITaxa;

public class Pessoa implements ITaxa

{

public function Pessoa()

{

}

public function getVariacaoTaxa():Number

{

return 0;

}

}

}

Basta alterar o valor do método getVariacaoTaxa(). No programa principal,

podemos criar a instância das duas classes e usar a interface para obter o

valor da taxa, veja:

Page 68: Dominando action script3

package

{

import flash.display.Sprite;

import pessoas.Pessoa;

import taxas.ITaxa;

import veiculos.Carro;

public class HelloWorld extends Sprite

{

public function HelloWorld()

{

var tiposSegurados:Array = [new Pessoa(),new

Carro()];

for each (var segurado:Object in

tiposSegurados )

{

if (segurado is ITaxa)

{

trace((segurado as

ITaxa).getVariacaoTaxa());

}

}

}

}

}

Neste exemplo criamos um array com as duas classes e depois usamos um for

each para percorrer cada uma das classes e obter o valor da taxa, fazendo um

typecast – uma conversão simples de tipo.

Aplicando mais interfaces a uma mesma classe

Você pode criar interfaces para “marcar” uma classe com um determinado

comportamento. Por exemplo, suponha que você queira marcar as classes que

possuem seguro com ISegurado. A interface ISegurado não possui nenhum

método, e serve apenas para marcar o comportamento de uma classe:

package seguro

{

public interface ISegurado

Page 69: Dominando action script3

{

}

}

e:

package veiculos

{

import seguro.ISegurado;

import taxas.ITaxa;

public class Carro implements ITaxa, ISegurado

{

//.......

}

}

Podemos criar e implementar quantas interfaces forem necessárias.

Dica: É bom ter um correto entendimento de interfaces pois elas ajudam muito na maioria do entendimento dos padrões de projeto existentes.

Acoplamento e interfaces

Outra utilidade das interfaces é gerar diminuir o acoplamento entre as classes.

Acoplamento é o quanto uma classe é dependente da outra. Por exemplo,

suponha que a roda de carro fosse soldada. Não existem parafusos que

retiram a roda, e se o pneu furar, você perde o carro.

Esse forte acoplamento provoca diversos problemas. Inicialmente ninguém

vai querer comprar um carro assim, e se comprar, não poderá trocar o pneu

nunca. Para resolver este problema (ainda estamos no mundo real), existe

uma interface entre a roda e o carro. O carro deve possuir uma entrada para

parafusos no diâmetro correto, além de espaçamento idêntico as entradas da

roda.

Veja que o carro não tem conhecimento da roda em si, e que apenas sabe que

deve implementar aquela estrutura para que algo como uma roda seja

acoplada.

Page 70: Dominando action script3

As interfaces possuem exatamente este comportamento. Uma classe apenas

conhece a interface, e não mais a outra classe que está acoplada. Voltando a

OO, suponha que tenhamos agora a classe motor. Todo carro precisa da

classe motor, então podemos criar:

package motores

{

public class Motor

{

public function Motor()

{

}

}

}

E que agora, o carro implemente a classe motor, criando um forte

acoplamento:

package veiculos

{

import motores.Motor;

import seguro.ISegurado;

import taxas.ITaxa;

public class Carro implements ITaxa, ISegurado

{

protected var motor:Motor;

public function Carro()

{

_rodas = 4;

motor = new Motor();

}

//.......

Veja que, neste caso, criamos um forte acoplamento entre duas classes. Ou

seja, uma classe não vive sem a outra. Suponha que, em um determinado

estágio do programa (por exemplo, após 6 meses de uso), você precise criar

derivações do motor, pois agora existem motores de carro e motores de

lancha. Você precisará manualmente alterar a classe Carro, e fazer as

modificações, possivelmente gerando um acoplamento entre Carro e

MotorCarro. Isso é muito ruim para o seu programa, pode gerar problemas e

Page 71: Dominando action script3

bugs que antes não existiam e pode inclusive alterar o comportamento normal

de suas classes.

Quando programamos de olho nas modificações futuras, sabemos que não

podemos criar esse forte acoplamento e usamos interfaces para resolver o

problema. A interface faz com que a classe Carro use apenas as

funcionalidades do motor que ela precisa, ou seja, a classe Carro agora

conecta-se a interface do motor e não ao motor propriamente dito.

Vamos ao código então, inicialmente criando a interface IMotor:

package motores

{

public interface IMotor

{

function Acelerar():void;

}

}

E vamos implementar essa interface na classe Motor:

package motores

{

public class Motor implements IMotor

{

public function Motor()

{

}

public function Acelerar():void

{

//aqui o código para acelerar

}

}

}

Finalmente, a classe Carro agora acoplada a uma interface e não mais a uma

classe:

package veiculos

{

import motores.IMotor;

import motores.Motor;

import seguro.ISegurado;

Page 72: Dominando action script3

import taxas.ITaxa;

public class Carro implements ITaxa, ISegurado

{

protected var motor:IMotor;

public function Carro(motor:IMotor)

{

this.motor = motor;

_rodas = 4;

}

//...........

Veja que criamos uma propriedade Motor na classe Carro, mas que até este

momento ainda não instanciamos ou criamos alguma referência entre o carro

e o motor. Nesse contexto entra outro conceito, de deixar que a

implementação da classe atribua o motor, ou seja, assim que instanciamos a

classe Carro, passamos a instância do motor em si, veja:

package

{

import flash.display.Sprite;

import motores.Motor;

import veiculos.Carro;

public class HelloWorld extends Sprite

{

public function HelloWorld()

{

var carro:Carro = new Carro(new Motor());

}

}

}

Com isso podemos criar um carro com diversos tipos de motores, mas

somente aqueles que possuírem a interface IMotor. Independente da classe de

motor que existir, o que vale para a classe carro é a interface IMotor, gerando

um acoplamento fraco entre a classe Carro (e suas derivadas) e a classe

Motor.

Page 73: Dominando action script3

Pensamento do leitor: Até entendi, mas onde vou aplicar isso no meu dia a dia? Não faço a mínima idéia!! Resposta: Todos sabemos que estamos direcionando nossos estudos ao Flex e que se a sua necessidade é apenas criar formulários para inserir dados e criar Grids para exibir dados, não faz sentido se preocupar com interfaces. Mas quando vamos além disso, como por exemplo gerenciar as janelas abertas na aplicação, ou processos ocorrendo no sistema, o uso de interfaces começa a tornar-se interessante. Idéias onde as interfaces nos ajudam: 1) Em um sistema de restaurante, você deseja exibir visualmente as mesas que estão desocupadas, além de exibir mesas que estão fechando a conta. Se você criar um sistema fortemente acoplado, quando o seu chefe pedir um novo status, por exemplo, quando o cliente da mesa faz o pedido, possivelmente você terá problemas em inserir esse comportamento no seu sistema. Com o pensamento mais aberto e implementando interfaces, possivelmente você apenas definirá uma nova classe, por exemplo MesaFazendoPedido, que implementa uma interface chamada IDesign que possui o método CorPadrao, e mais algumas interfaces que o sistema precisa, e pronto, você terá a funcionalidade pronta sem muito custo.

2) Você está usando as classes do MDIWinodow do Flex, e como lá existem muitos métodos e você quer apenas usar alguns, você pode usar uma interface para filtrar estes métodos. A interface se chama IJanela, de forma a ficar fácil a manipulação de alguns comandos como minimizar ou fechar.

Bom, estes são apenas alguns exemplos. Somente a prática mesmo para ver

que vale a pena. Lembre-se que todo o esforço e dedicação ao uso de padrões

de projeto e interfaces é destinado a melhorar a manutenção do seu código,

como o seu entendimento. Você estará programando para sofrer menos no

futuro, e não para criar código mais rápido no presente. Veremos mais a

respeito de padrões de projeto no último capítulo desta obra.

Classes dinâmicas

O Action Script permite que uma classe seja dinâmica, possibilitando que

novas variáveis possam ser inseridas dinamicamente em tempo de execução.

Para tornar uma classe dinâmica, basta inserir a palavra dynamic na criação

da classe, confirme o exemplo a seguir:

Page 74: Dominando action script3

public dynamic class Carro implements ITaxa, ISegurado

{

protected var motor:IMotor;

//........

Dessa forma, podemos, em tempo de execução, adicionar propriedades a

classe, como neste exemplo:

public function HelloWorld()

{

var carro:Carro = new Carro(new Motor());

carro.Nome = "Fox";

carro.Kms = 4000;

carro.Cidades = new Array();

(carro.Cidades as Array).push("Rio de

Janeiro", "São Paulo", "Cabo frio");

trace("Meu carro: " + carro.Nome);

trace("Kms rodados: " + carro.Kms);

trace("Cidades:");

for each (var cidade:String in carro.Cidades)

trace(" " + cidade);

}

O resultado seria:

Meu carro: Fox

Kms rodados: 4000

Cidades:

Rio de Janeiro

São Paulo

Cabo frio

Page 75: Dominando action script3

Conhecendo a API

Agora que já compreendemos o básico da Orientação a Objetos, podemos

começar a usufruir das principais vantagens de uma linguagem moderna e de

um rico conjunto de classes para nos auxiliar nas tarefas mais comuns, como

manipular Strings, Datas, fazer buscas em XML e Arrays, manipular

ByteArrays etc.

Este capítulo trata especialmente dos principais métodos das principais

classes do Action Script. É necessário conhecer esses métodos para agilizar o

desenvolvimento em si e para que não seja necessário realizar

implementações que já foram criadas pelo time da Adobe.

String

A classe String trata especialmente de texto, e possui as seguintes

propriedades/métodos:

length

Determina a quantidade de caracteres que forma a string.

charAt

Retorna o caractere de acordo com o índice passado. Para obter o último

caractere, pode-se usar a propriedade: length()-1

Page 76: Dominando action script3

concat

Usado para concatenar strings, realizando as conversões quando necessário.

Ou seja, não é preciso chamar o método toString para números ou datas.

Exemplo:

var nome:String = " Daniel "

trace(nome.concat(" Schmitz, nasceu em ", new

Date(1980,0,11) ) ) ;

Resultado:

Daniel Schmitz, nasceu em Fri Jan 11 00:00:00 GMT-0200

1980

indexOf

Usado para obter o índice de um segmento de texto no texto principal. É

comumente usado para sabermos se uma string contém algum caractere

específico, como no exemplo a seguir:

var expressao:String = "Daniel|[email protected]"

if ( expressao.indexOf("|") != -1)

{ //Existe o |

//aqui o código para quebrar a string em 2 pedaços

}

Veja que se a string procurada não for encontrada, o retorno será -1. Então

para verificarmos se uma string contém uma expressão, basta comparar com

o valor -1.

lastIndexOf

Tem o mesmo efeito do indexOf, mas busca uma string no texto partindo da

direita para a esquerda.

match

Faz uma comparação na string e retorna um array de strings que “batem” com

a comparação. Esta comparação é feita através de uma expressão regular. O

Page 77: Dominando action script3

exemplo a seguir faz com que os emails que estão separados por vírgula

sejam adcionados a um Array.

var expressao:String = "[email protected],

[email protected]";

var emails:Array =

expressao.match(/\w*@\w*\.[org|com|com.br]+/g);

for each(var email:String in emails)

trace(email);

Resultado:

[email protected]

[email protected]

replace

Realiza a troca de uma expressão por outra. A expressão de busca é realizada

através de expressão regular. Suponha que em um texto você queria trocar

“Brazil” por “Brasil”:

var texto:String = " Estamos no Brazil agora ";

texto = texto.replace(/Brazil/,"Brasil");

trace(texto); // Estamos no Brasil agora

search

Busca por uma expressão no texto, retornando o índice do primeiro caractere

que “bater” com a expressão.

split

Retorna um array de items que batem com uma expressão regular em um

texto. Por exemplo:

var texto:String = " Fulano1, Fulano2, Fulano3 ";

for each (var nome:String in texto.split(/,/))

trace(nome);

Resultado:

Page 78: Dominando action script3

Fulano1

Fulano2

Fulano3

Neste exemplo inserimos o comando split dentro do for each. Isto é

perfeitamente possível já que o comando split retorna um Array.

substr

Retorna uma seqüência de caracteres dado uma posição inicial e uma

quantidade qualquer. Não é muito usada porque as expressões regulares

conseguem de certa forma suprir esta necessidade.

substring

Possui um comportamento semelhante ao substr, mas ao invés de indicar a

quantidade de caracteres a serem extraídos, informamos a posição final do

mesmo.

Por exemplo, suponha que você queira extrair o primeiro nome de uma

pessoa:

var nome:String = "Daniel Schmitz";

trace(nome.substring(0,nome.indexOf(" "))); //Daniel

toLowerCase

Converte todos os caracteres de uma string para minúsculo.

toUpperCase

Converte todos os caracteres de uma string para maiúsculo.

Array

length

Retorna a quantide de itens do Array

Page 79: Dominando action script3

concat

Usado para concatenar duas ou mais arrays. Você pode juntar uma array

com dois elementos e outra com três, resultando em um array de 5

elementos.

every

Este método executa um teste em cada elemento do array. Este teste é

definido por uma função, que pode ser anônima. O método every retorna

falso se um dos itens não passar na validação.

Por exemplo, suponha que você tenha um array de emails e você quer testar

se estes emails estão válidos. Vamos supor, para facilitar, que para um email

ser válido, basta encontrar o caractere @. Então o código completo fica:

public function HelloWorld()

{

var emails:Array = ["[email protected]",

"[email protected]",

"[email protected]",

"fulano4email.com",

"[email protected]"

];

if (emails.every(checkEmail))

trace("Todos os emails ok");

else

trace("Algum email com problema");

}

public function checkEmail(email:String, index:int,

arr:Array):Boolean

{

return email.indexOf("@")!=-1;

}

filter

Page 80: Dominando action script3

Possui um funcionamento semelhante ao every, mas ao invés de retornar

verdadeiro ou falso, o filter retorna um novo Array, somente com os

elementos que satisfazem a condição. Vamos aproveitar o exemplo anterior e

criar um novo exemplo, onde dado um array de elementos, obtemos somente

elementos que são emails (possuem um @):

public function HelloWorld()

{

var palavras:Array = ["[email protected]",

"[email protected]",

"daniel",

"fulano4email.com",

"[email protected]"

];

var emails:Array = palavras.filter(checkEmail);

for each ( var email:String in emails)

trace(email);

}

public function checkEmail(email:String, index:int,

arr:Array):Boolean

{

return email.indexOf("@")!=-1;

}

Resultado:

[email protected]

[email protected]

[email protected]

forEach

Este método executa uma função para cada item de um array. A idéia é a

mesma dos métodos anteriores.

var numeros:Array = [2,3,4,5,6];

numeros.forEach(function(numero:int, index:int,

arr:Array):void

{

arr[index] = numero * 2;

});

Page 81: Dominando action script3

for each ( var numero:String in numeros)

trace(numero);

Resultado:

4

6

8

10

12

Neste exemplo temos duas novidades. A primeira é que criamos uma função

anônima, e a segunda é que usamos os outros parâmetros da função anônima,

que são o índice atual do Array (index) e o próprio Array (arr),

respectivamente. Com esses dois parâmetros adicionais, pode-se alterar os

elementos de acordo com a necessidade.

indexOf

Retorna o índice de um elemento, lembrando que o elemento procurado deve

ser idêntico ao elemento que está no array.

lastIndexOf

Comportamento semelhante ao indexOf, mas começa a busca pelo final do

array.

join

Retorna uma string que é a união de todos os elementos de um Array

separados por um delimitador pré definido. Exemplo:

var nomes:Array = ["fulano1",

"fulano2",

"fulano3",

"fulano4"

];

trace(nomes.join(", "));

Resultado:

Page 82: Dominando action script3

fulano1, fulano2, fulano3, fulano4

map

Este método possui um comportamento semelhante ao forEach, com a

diferença de retornar um novo array, baseado na função executada para cada

item do array. Vamos repetir o exemplo do forEach para entendermos o seu

comportamento:

public function HelloWorld()

{

var numeros:Array = [2,3,4,5,6];

trace (numeros.map(dobrar).join(","));

}

public function dobrar(num:int,index:int,arr:Array):int

{

return num*2;

}

Resultado

4,6,8,10,12

Veja que neste código usamos o map, que retorna um array e logo depois

usamos o join para concatenar todos os itens do array em uma única string.

pop

Retira e retorna último elemento adicionado no Array.

push

Adiciona um elemento no Array.

reverse

Reverte os elementos de um array. O primeiro elemento vai para o último, e

assim por adiante.

Page 83: Dominando action script3

shift

Remove e retorna o primeiro elemento adicionado no Array.

slice

Retorna uma nova array através de uma faixa de elementos de um outro

Array.

some

Executa um teste para cada elemento do array, através de uma função de

callback (como no método filter), mas quando a função de callback retorna

verdadeiro, o teste pára e o método também retorna verdadeiro. Este método

é útil para avaliar um array que possui muitos itens, e que todos os itens

tenham uma particularidade. No exemplo a seguir, temos que somar todos os

elementos de um array, mas para isso precisamos nos certificar que cada

elemento é um número. Podemos usar o some para isso, e na primeira vez

que encontrarmos um elemento que não é um número, o loop entre os

elementos restantes não será executado.

public function HelloWorld()

{

var numeros:Array = [2,3,4,5,6,'noNum',8,9,10];

if (numeros.some(isNotNum))

trace("Erro: Nem todos os elementos são números");

else

trace("Ok: Todos os elementos sao números");

}

public function isNotNum(num:*,index:int,

arr:Array):Boolean

{

trace("avaliando ",num);

return !(num is Number);

}

Resultado:

Page 84: Dominando action script3

avaliando 2

avaliando 3

avaliando 4

avaliando 5

avaliando 6

avaliando noNum

Erro: Nem todos os elementos são números

sort

O método sort é usado para ordenar os elementos de um array. O uso do sort

sozinho estipula uma regra simples de ordenação, baseada no código Unicode

do carectere (Então “Z” vem antes de “a”).

Para melhorar o uso do sort, podemos criar uma função de callback que irá

avaliar os itens a serem ordenados. Esta função deverá retornar um número

inteiro, que pode ser:

-1 quando o primeiro elemento deve estar antes do segundo elemento

0 quando os elementos são iguais

1 quando o primeiro elemento deve estar depois do segundo elemento

Vamos a um exemplo simples. Suponha que tenhamos um array de objetos e

que cada objeto tenha as propriedades nome e idade. Agora suponha que

queremos ordenar estes objetos, de acordo com a idade de cada objeto do

array:

public function HelloWorld()

{

var arr:Array = new Array();

arr.push({Nome:'Fulano1',Idade:12});

arr.push({Nome:'Fulano2',Idade:32});

arr.push({Nome:'Fulano3',Idade:22});

arr.push({Nome:'Fulano4',Idade:2});

arr.push({Nome:'Fulano5',Idade:72});

arr.push({Nome:'Fulano6',Idade:52});

arr.sort(ordenaIdade);

arr.forEach(mostraIdade);

}

Page 85: Dominando action script3

public function ordenaIdade(obj1:*,obj2:*):int

{

if (obj1.Idade > obj2.Idade) return 1;

if (obj1.Idade < obj2.Idade) return -1;

return 0;

}

public function

mostraIdade(item:*,index:int,arr:Array):void

{

trace(item.Nome,item.Idade);

}

sortOn

O método sortOn é usado justamente quando queremos ordenar um array de

objetos. Na verdade ele faz exatamente a mesma coisa que o exemplo

anterior, só que precisamos passar apenas a propriedade do objeto em que

queremos ordenar. Além da propriedade a ser ordenada, temos que repassar

como esse objeto será ordenado, pois para propriedades numéricas,

precisamos informar que a ordenação será numérica e não baseada no código

Unicode. O exemplo a seguir mostra como ordenar por nome e como ordenar

por idade:

public function HelloWorld()

{

var arr:Array = new Array();

arr.push({Nome:'Fulano5',Idade:12});

arr.push({Nome:'Fulano4',Idade:32});

arr.push({Nome:'Fulano3',Idade:22});

arr.push({Nome:'Fulano2',Idade:2});

arr.push({Nome:'Fulano1',Idade:72});

arr.push({Nome:'Fulano6',Idade:52});

arr.sortOn("Nome");

trace("Ordenado por nome");

arr.forEach(mostraObj);

arr.sortOn("Idade", Array.NUMERIC);

trace("Ordenado por idade");

arr.forEach(mostraObj);

}

Page 86: Dominando action script3

public function mostraObj(item:*,index:int,arr:Array):void

{

trace(" ",item.Nome,item.Idade);

}

Resultado:

Ordenado por nome

Fulano1 12

Fulano2 32

Fulano3 22

Fulano4 2

Fulano5 72

Fulano6 52

Ordenado por idade

Fulano4 2

Fulano1 12

Fulano3 22

Fulano2 32

Fulano6 52

Fulano5 72

unshift

Adiciona elementos no início do Array

Date

A classe Date é usada para manipular data e hora. Geralmente instanciamos

um objeto que contém a informação sobre uma data qualquer. Podemos

repassar esta data ou então obter a data atual. A partir da data, podemos

realizar operações e obter informações sobre aquela data em questão.

Além de métodos a classe Date possui diversas propriedades que representam

alguma informação da data em si.

date

Usado para retornar o dia do mês, um valor que pode ir de 1 a 31.

dateUTC

Page 87: Dominando action script3

O mesmo que a propriedade date, mas usando a data universal (universal

coordinate time). Todas as propriedades possuem a sua forma UTC, então

não será necessário comentar todas elas.

day

Retorna o dia da semana (0 é domingo e 6 é sábado).

fullYear

Retorna o ano com quatro dígitos.

hours

Retorna a hora (0 a 23).

milliseconds

Retorna os milisegundos (0 a 999).

minutes

Retorna os minutos da data (0 a 59).

month

Retorna o mês (0 a 11).

seconds

Retorna os segundos (0 a 59).

time

Representa o número de milisegundos desde 1 de janeiro de 1970.

Page 88: Dominando action script3

toDateString

Retorna a representação da data sem a informação da hora

toString

Retorna uma string com a informação da data e da hora, no seguinte formato:

Wed Apr 12 15:30:17 GMT-0700 2006

toTimeString

Retorna somente a informação da hora

Math

A classe Math possui métodos específicos para o cálculo de operações

matemáticas. Além disso possui algumas constantes como o PI e o LN10

(logaritmo na base 10).

Para acessar o número PI, basta usar:

trace(Math.PI); // 3.141592653589793

Ao contrário de classes como Date, Array ou String, o Math contém um

conjunto de métodos estáticos, que são acessados diretamente pela classe,

veja:

Math.<nome do método>();

abs

Retorna o número absoluto de um número. Um número absoluto é sempre

um número positivo.

cos,sin, tan

Retorna o cosseno, seno ou tangente de um ângulo em radianos

Page 89: Dominando action script3

log

Retorna o valor do logaritmo na base natural E (Math.E)

floor

Retorna o número inteiro mais próximo de um número fracionado, como por

exemplo “2.12”.

max

Retorna o maior número dado uma seqüência de números. Por exemplo:

trace(Math.max(1,2,3,4,5,3,12,5,22,7)); // 22

min

Retorna o menor número dado uma seqüencia de números

pow

Eleva um número a potência de outro número. Por exemplo:

trace(Math.pow(2,3)); // 8

random

Retorna um número randômico entre 0 e 1

sqrt

Retorna a raiz quadrada de um número

Object

A classe Object é a classe no mais alto nível do Action Script 3.0. Isso

significa que quase todas as classes do Action Script 3.0 possuem como

classe base, o Object.

Page 90: Dominando action script3

hasOwnProperty

Este método retorna verdadeiro ou falso indicando se uma propriedade está

presente no objeto. Você pode usar este método para descobrir se um objeto

possui a propriedade que você precisa, principalmente em objetos dinâmicos.

No código a seguir, onde ordenamos um conjunto de objetos pela

propriedade Idade, podemos verificar pelo menos se a propriedade existe.

public function HelloWorld()

{

var arr:Array = new Array();

arr.push({Nome2:'Fulano5',Idade:12});

arr.push({Nome:'Fulano4',Idade:32});

arr.push({Nome:'Fulano3',Idade:22});

arr.push({Nome:'Fulano2',Idade:2});

arr.push({Nome:'Fulano1',Idade:72});

arr.push({Nome:'Fulano6',Idade:52});

if (!arr.some(NaoPossuiNome))

{

arr.sortOn("Nome");

trace("Ordenado por nome");

arr.forEach(mostraObj);

}

if (!arr.some(NaoPossuiIdade))

{

arr.sortOn("Idade", Array.NUMERIC);

trace("Ordenado por idade");

arr.forEach(mostraObj);

}

}

public function mostraObj(item:*,index:int,arr:Array):void

{

trace(" ",item.Nome,item.Idade);

}

public function

NaoPossuiNome(item:Object,index:int,arr:Array):Boolean

{

return !item.hasOwnProperty("Nome");

}

Page 91: Dominando action script3

public function

NaoPossuiIdade(item:Object,index:int,arr:Array):Boolean

{

return !item.hasOwnProperty("Idade");

}

Resultado:

Ordenado por idade

Fulano2 2

undefined 12

Fulano3 22

Fulano4 32

Fulano6 52

Fulano1 72

propertyIsEnumerable

Indica se uma propriedade possui items que são enumeráveis. Com isso

garantimos que podemos realizar um laço for...each .

Page 92: Dominando action script3

Eventos

O Action Script 3.0 é uma linguagem tipicamente orientada a eventos. Neste

capítulo, estaremos esclarecendo como associar eventos a métodos e como

criar novos eventos para suas classes.

O que é um evento?

Um evento pode ser associado a um acontecimento no sistema. Este

acontecimento possui informações, tais como quem executou o evento e

como ele está se propagando. Um exemplo de evento é quando a aplicação

está pronta para ser executada, ou seja, quando tudo que precisa ser carregado

na memória está pronto. Então a aplicação dispara um evento, informando

este acontecimento.

Outro evento é o click do botão do mouse, ou então a ação de fechar uma

janela. A maioria das classes do Action Script 3.0 possuem eventos. Por

exemplo, a classe Sprite, da qual vimos em todos os exemplos, possui os

eventos click, doubleClick, added e muitos outros! Para conhecer estes

eventos, fique de olho na API do Action Script 3.0.

Definições

Existem alguns conceitos relacionados a eventos que devemos conhecer,

sendo eles destacados a seguir:

Tipo de evento

Todo evento possui um tipo (uma classe) e todo evento herda da classe Event.

O evento criado é repassado para o método listener, que pode ser usado para

Page 93: Dominando action script3

obter mais informações sobre o evento. Como o evento é uma classe, você

pode adicionar propriedades ou métodos extras na classe. Por exemplo, o

evento Click possui em suas propriedades a coordenada X e Y do mouse, no

momento em que o evento foi disparado.

Target

O target (alvo) é justamente o componente/objeto que disparou o evento. Por

exemplo, quando um botão dispara o evento mouseOver, o target é o botão.

O target mantém-se durante toda a fase de vida do evento.

Dispatcher

O termo dispatch refere-se ao disparo do evento. É realizado nas classes onde

o evento é disparado. Esse disparo é realizado através do método

dispatchEvent, um método da classe EventDispatcher.

Listener

É o objeto que se registra ao dispatcher para receber os eventos. O listener

tem o objeto de chamar o handler associado àquele evento.

Handler

É a função que é chamada quando o evento é disparado.

Como trabalhar com eventos

Agora que conhecemos o conceito de eventos, podemos usá-los através do

método addEventListener. Este método, como o próprio nome diz, adiciona

um listener a um evento, ou seja, ele relaciona um evento a um método.

Na classe HelloWorld, podemos por exemplo adicionar um listener no evento

que diz que a aplicação está pronta para uso. O código para criar esse

comportamento está definido a seguir:

Page 94: Dominando action script3

package

{

import flash.display.Sprite;

import flash.events.Event;

public class HelloWorld extends Sprite

{

public function HelloWorld()

{

trace("iniciando...");

this.addEventListener(Event.ADDED_TO_STAGE,OnSpriteAddToS

tage);

trace("fim do construtor...");

}

private function

OnSpriteAddToStage(event:Event):void

{

trace("HelloWorld foi adicionado ao stage");

}

}

}

Resultado:

iniciando...

fim do construtor...

HelloWorld foi adicionado ao stage

Este código traz uma particularidade dos eventos. Eles são assíncronos.

Algo assíncrono diz que não se sabe ao certo quando vai ocorrer. No nosso

exemplo, veja que o trace dos construtores são chamados primeiro em

relação ao trace do evento. Ou seja, quando fazemos o addEventLisntener

não estamos automaticamente chamando o método OnSpriteAddToStage. Ele

será chamado somente quando o evento ADDED_TO_SATE for disparado.

Isso acontece momentos depois do construtor da classe HelloWorld ser

executado.

Page 95: Dominando action script3

Como criar eventos

Agora que aprendemos a usar os eventos disponíveis nas classes do Action

Script 3.0, vamos criar o nosso próprio evento.

Imagine que você esteja criando uma classe para somar dois números, e que

deseja disparar eventos quando a soma der um resultado negativo, e quando a

soma ultrapassar o valor 100. Você quer disparar um evento também sempre

quando a soma for finalizada.

Inicialmente podemos criar a classe que conterá estes eventos. Esta classe

deverá herdar de Event. No projeto HelloWorld, vá até File, New,

ActionScript Class:

Assim que criar a classe do evento, precisamos criar algumas constantes

estáticas que definem quais são os eventos. O código até este momento é o

seguinte:

package events

{

Page 96: Dominando action script3

import flash.events.Event;

public class CalculosEvent extends Event

{

public static const RESULT_OVER100:String =

"CalculosEvent_RESULT_OVER100";

public static const RESULT_NEGATIVE:String =

"CalculosEvent_RESULT_NEGATIVE";

public static const RESULT:String =

"CalculosEvent_RESULT";

public function CalculosEvent(type:String,

bubbles:Boolean=false, cancelable:Boolean=false)

{

super(type, bubbles, cancelable);

}

}

}

Estas constantes serão usadas no momento em que adicionarmos um listener

para elas. Como abordamos no tópico anterior, o evento é uma classe e

podemos adicionar propriedades a ele. Suponha então que queremos inserir

os valores do resultado, lembrando que estamos somando dois números.

Então podemos alterar o código do evento para:

package events

{

import flash.events.Event;

public class CalculosEvent extends Event

{

public static const RESULT_OVER100:String =

"CalculosEvent_RESULT_OVER100";

public static const RESULT_NEGATIVE:String =

"CalculosEvent_RESULT_NEGATIVE";

public static const RESULT:String =

"CalculosEvent_RESULT";

public var valor1:int;

public var valor2:int;

Page 97: Dominando action script3

public function CalculosEvent(type:String,

valor1:int, valor2:int, bubbles:Boolean=false,

cancelable:Boolean=false)

{

this.valor1 = valor1;

this.valor2 = valor2;

super(type, bubbles, cancelable);

}

}

}

Criamos duas variáveis, que serão preenchidas no construtor do evento.

Agora que a classe relativa ao evento está pronta, podemos criar a classe que

fará o cálculo. Veja:

package matematica

{

import events.CalculosEvent;

import flash.events.EventDispatcher;

import flash.events.IEventDispatcher;

Page 98: Dominando action script3

public class Calculos extends EventDispatcher

{

public function

Calculos(target:IEventDispatcher=null)

{

super(target);

}

public function Sum(valor1:int,valor2:int):int

{

var sum:int = valor1+valor2;

if (sum > 100)

dispatchEvent(new

CalculosEvent(CalculosEvent.RESULT_OVER100,valor1,valor2))

;

if (sum < 0)

dispatchEvent(new

CalculosEvent(CalculosEvent.RESULT_NEGATIVE,valor1,valor2)

);

dispatchEvent(new

CalculosEvent(CalculosEvent.RESULT,valor1,valor2));

return sum;

}

}

}

Nesta classe, usamos o método dispatchEvent para disparar um evento. Este

método está disponível porque a classe Calculos herda de EventDispatcher.

Quando usamos o dispatchEvent, criamos o evento CalculosEvent repassando

as constantes de acordo com a situação desejada. Veja que repassamos a

constante novamente, e os valores da soma.

Finalmente, para finalizarmos a aplicação, editamos a classe HelloWorld

instanciando a classe de Calculos e adicionando os listeners necessários,

veja:

package

{

import events.CalculosEvent;

import flash.display.Sprite;

import flash.events.Event;

Page 99: Dominando action script3

import matematica.Calculos;

public class HelloWorld extends Sprite

{

public function HelloWorld()

{

var c:Calculos = new Calculos();

c.addEventListener(CalculosEvent.RESULT,OnResult);

c.addEventListener(CalculosEvent.RESULT_NEGATIVE,

OnResultNegative);

c.addEventListener(CalculosEvent.RESULT_OVER100,

OnResultOver100);

c.Sum(10,20);

c.Sum(90,20);

c.Sum(10,-20);

c.Sum(0,10);

}

private function OnResult(e:CalculosEvent):void

{

trace(" Result: ",e.valor1,e.valor2);

}

private function

OnResultNegative(e:CalculosEvent):void

{

trace(" Negative Result:

",e.valor1,e.valor2);

}

private function

OnResultOver100(e:CalculosEvent):void

{

trace(" Over 100 Result:

",e.valor1,e.valor2);

}

}

}

Page 100: Dominando action script3

Resultado:

Result: 10 20

Over 100 Result: 90 20

Result: 90 20

Negative Result: 10 -20

Result: 10 -20

Result: 0 10

Agora você pode compreender melhor como todo o sistema baseado em

eventos funciona. Após criar o evento e a classe que dispara ele, podemos

usar o método addEvenetListener para capturar o evento disparado e

executar um método ou função anônima.

Talvez esse exemplo seja simples demais para que possamos entender o

poder da programação orientada a eventos, mas imagine que estamos criando

uma calculadora e que queremos deixar o valor em vermelho caso ele seja

negativo. O primeiro passo foi dado, pois quando a classe dispara o evento do

valor negativo, podemos facilmente alterar o status visual da calculadora.

No framework Flex, e em seus componentes, você verá o uso extensivo de

eventos e acabará se acostumando com eles, com a facilidade que eles

proporcionam e com o ganho de produtividade. Inclusive todos os

frameworks para Flex como o swiz são baseado em eventos.

Page 101: Dominando action script3

Integração com o Flex

Durante toda esta obra estamos comentando sobre o Flex e o Flash Builder.

No início instalamos o Flash Builder e a partir dele criamos todos os nossos

exemplos. Agora vamos ampliar nosso conhecimento sobre a ferramenta

Flash Builder, mas sempre voltado ao Action Script.

Criando o projeto Flex

Com o Flash Builder aberto, acesse o menu File, New, Flex Project. Para o

campo Project name, escolha HelloFlex e em seguida clique no botão Finish.

Este assistente possui diversas configurações, mas que não são pertinentes

neste momento.

Ao criar o projeto, podemos perceber que o arquivo HelloFlex.mxml é aberto,

que com a linguagem MXML da aplicação ativada. Veja que até este

momento não temos nenhum código Action Script 3.0, apenas temos o

código MXML. Mas o Action Script 3.0 estará presente em quase tudo que

você fizer.

Vamos a um pequeno teste. Na tag <s:Application ...> existe um evento

chamado creatonComplete. Adicione-o dentro da tag e use a

complementação de código para gerar o handler do evento. Veja:

Page 102: Dominando action script3

Ao gerar o handler, temos o seguinte código:

<?xml version="1.0" encoding="utf-8"?>

<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"

xmlns:s="library://ns.adobe/flex/spark"

xmlns:mx="library://ns.adobe.com/flex/mx"

minWidth="955" minHeight="600"

creationComplete="OnComplete(event)"

>

<fx:Script>

<![CDATA[

import mx.events.FlexEvent;

protected function OnComplete(event:FlexEvent):void

{

// TODO Auto-generated method stub

}

]]>

</fx:Script>

<fx:Declarations>

<!-- Place non-visual elements

(e.g., services, value objects) here -->

</fx:Declarations>

Page 103: Dominando action script3

</s:Application>

Como podemos ver, ao definir um handler para o evento creationComplete,

caímos na linguagem Action Script 3.0, onde podemos usar tudo que

aprendemos até agora.

Importando bibliotecas

O Flex possui um conjunto muito bom de bibliotecas que podem ser

incorporadas nos projetos. A maioria delas apresenta um arquivo com a

extensão swc, no qual podemos baixar e usar.

Vamos incorporar em nosso projeto a biblioteca flexlib, que já possui uma

versão para o Flex 4. Inicialmente acesse o site oficial da biblioteca:

http://code.google.com/p/flexlib/

Na lado direito, em Featured Downloads, clique no link “flexlib – 2.5 –

flex4.zip”. Baixe o arquivo e descompacte-o. Ao abrir o conteúdo do zip,

temos os seguintes arquivos/pastas:

Neste momento precisamos do arquivo swc, que é justamente toda a

biblioteca flexlib compilada e pronta para uso. Voltando ao projeto

Page 104: Dominando action script3

HelloFlex, no Flash Builder, vamos incorporar esta biblioteca para o nosso

projeto. Para isso, acesse as propriedades do projeto HelloFlex, clicando com

botão direito do mouse sobre o projeto e escolhendo Properties:

Quando a janela de propriedades surgir, navegue até o item Flex Build Path e

na aba Library Path,clique no botão “Add SWC”:

Page 105: Dominando action script3

Na janela que abre, clique no botão Browse, e selecione o arquivo

flexlib.swc.Clique em Ok para finalizar e repare que a biblioteca foi inserida

com sucesso:

Page 106: Dominando action script3

Clique em OK para fechar a tela de propriedades do projeto HelloFlex, e

acesse o arquivo HelloFlex.mxml. Dentro da tag fx:Script, vamos fazer um

pequeno teste, verificando se a biblioteca flexlib está disponível para uso.

Para isso use o comando import, dentro da tag <fx:Script, faça o seguinte:

Page 107: Dominando action script3

Veja que ao usar o import, podemos importar a biblioteca flexlib. Também

pode-se acessar o modo design e verificar os componentes que foram

adicionados na aba Components.

Criando sua própria biblioteca Action Script

É muito recomendável que você crie uma biblioteca Action Script

(chamaremos de lib) para os seus projetos, observando algumas dicas:

Crie uma biblioteca global, que poderá ser adicionada a qualquer

projeto Flex existente.

Crie uma biblioteca relacionada ao projeto em si. Nessa biblioteca

você coloca as classes Action Script que o projeto usa. No capítulo

anterior criamos diversas classes, relacionadas a pessoas, taxas,

veículos, matemática etc. Estas classes poderiam estar nessa

biblioteca.

Page 108: Dominando action script3

A separação do projeto em “camadas” traz benefícios como uma melhor

separação do código, possibilitando que equipes possam trabalhar com mais

eficiência.

Para criar uma biblioteca, navegue até File, New, Flex Library Project.

Vamos criar o projeto chamado gLib, que seria o projeto global a qualquer

outro projeto Flex:

Após criar o projeto, vamos criar uma classe qualquer, dentro de um package

apropriado. Por exemplo, vamos criar uma classe chamada Remote em um

pacote chamado connection, que estende de RemoteObject, que é uma classe

para conexões AMF do Flex com o servidor:

Page 109: Dominando action script3

Ao criarmos esta classe, temos o seguinte código:

package connection

{

import mx.rpc.remoting.mxml.RemoteObject;

public class Remote extends RemoteObject

{

public function Remote(destination:String=null)

{

super(destination);

}

}

}

Adicionando a biblioteca no projeto Flex

Agora que criamos a biblioteca glib, podemos facilmente adicioná-la ao

projeto HelloFlex. Acesse as propriedades do projeto HelloFlex e navegue até

Flex Build Path. Na aba Library Path, clique no botão Add Project e adicione

o projeto gLib.

Page 110: Dominando action script3

É importante que você adicione o projeto e não o arquivo SWC. Isso

acontece porque ao adicionar como projeto as atualizações no projeto gLib

serão automaticamente refletidas no projeto principal.

O flexlib adicionamos como SWC porque ele está pronto para uso, e não

sofrerá modificações.

Page 111: Dominando action script3

Como trabalhar com Action Script e MXML

Se você conhece HTML e JavaScript, possivelmente enxergou uma relação

entre o HTML e o MXML e o Action Script e JavaScript. Isso é verdade,

enquanto o MXML desenha a aplicação, o Action Script dá a lógica

necessária para ela.

Com isso temos um pequeno problema de organização. Como misturar esses

dois códigos sem prejudicar o entendimento do mesmo?

Utilizando arquivos Action Script externos

Algumas linguagens, como o .Net, tratam esta separação através de dois

arquivos separados, um contendo HTML e outro contendo código. Essa é

uma boa prática e podemos aplicá-la da seguinte forma:

No projeto HelloFlex, adicione um arquivo Action Script: File, New,

ActionScript File. Crie o arquivo HelloFlex.as. Este nome é o mesmo do

arquivo mxml, e de propósito, para que possamos saber que aquele arquivo

contém código relativo ao HelloFlex.mxml.

Até este momento temos a seguinte configuração do projeto:

Page 112: Dominando action script3

O que iremos fazer agora é adicionar o arquivo HelloFlex.as no

HelloFlex.mxml, da seguinte forma:

Page 113: Dominando action script3

Ou seja, através da propriedade source da tag <fx:Script/> conseguimos

adicionar um arquivo Action Script que possui somente código. Um pequeno

problema nesse aspecto é que quando usamos o Flash Builder para gerar os

nossos Handlers, o código será criado ainda no arquivo MXML, e você terá

que movê-lo manualmente para o arquivo Action Script.

Embutindo Action Script nos componentes

Outra forma de inserir Action Script no MXML é embuti-lo diretamente no

código. Pode parecer “sujo” a princípio, mas é uma solução que

particularmente gosto bastante. Vamos um exemplo simples, relacionado ao

evento de click do botão:

Page 114: Dominando action script3

<s:Button label="Click-me">

<s:click>

<![CDATA[

Alert.show("Hello Flex");

]]>

</s:click>

</s:Button>

Este formato é o ideal para pequenos códigos relativos a eventos de

componentes. Se for necessário escrever muito código, então o melhor é criar

uma função separada (handler).

Diretamente na propriedade de um componente

Esta opção deve ser usada apenas para atribuições rápidas de uma variável.

No exemplo a seguir, criamos uma variável chamada estadosSudeste. Depois,

embutimos na propriedade dataprovider do ComboBox a variável que possui

os dados, veja:

<fx:Script>

<![CDATA[

import mx.collections.ArrayCollection;

protected var estadosSudeste:ArrayCollection = new

ArrayCollection(["MG","SP","ES","RJ"]);

]]>

</fx:Script>

<s:ComboBox dataProvider="{estadosSudeste}"

enabled="{estadosSudeste.length==4}"/>

Também inserimos outro código Action Script na propriedade enabled.

Como esta propriedade é booleana, podemos retornar para ela true ou false, e

isso é feito através da condição estadosSudeste.length==4.

Utilizando <fx:Script>

Esta é a forma mais comum, inclusive a usada pelo Flash Builder na geração

de código. Recomenda-se ter apenas um fx:script com código, e que ele

esteja no início do arquivo MXML.

Page 115: Dominando action script3

Como estender componentes

Outro recurso muito utilizado no Action Script 3.0 é estender componentes

do Flex, e alterar de acordo com suas necessidades. Para fazer isso, basta

criar uma classe Action Script que herde de um componente Flex, como por

exemplo, o Button:

Crie a classe MyButton no projeto gLib

Código:

package components

{

import spark.components.Button;

public class MyButton extends Button

{

public function MyButton()

{

//TODO: implement function

super();

Page 116: Dominando action script3

}

}

}

Dessa forma podemos implementar novas funcionalidades para qualquer tipo

de componente. No caso do Button, poderíamos alterar o label inicial, da

seguinte forma:

public function MyButton()

{

label = " Botão ";

super();

}

Como também poderíamos adicionar novos eventos e funcionalidades. Além

disso, pode-se adicionar novas interfaces para ao componente e com isso

garantir um melhor domínio em sua aplicação.

A possibilidade de expansão é tão grande que demandaria um novo livro,

para documentar e esclarecer melhor todos estes passos. A princípio, vamos

apenas observar que com o Action Script 3.0 é possível fazer muito mais do

que apenas telas de cadastro, bastando apenas conhecer bem a linguagem e

padrões de projeto. Os padrões ajudam a criar sistemas maiores, sem criar

código excessivamente ruim, prezando sempre por uma melhor manutenção

do código.

Page 117: Dominando action script3

Aplicando padrões de projeto

Este capítulo aborda alguns padrões de projeto que são comuns em qualquer

linguagem de programação OO. É importante perceber que os padrões de

projeto são extremamente úteis em diversas situações, e que abordar todos

eles nesta obra daria uma nova obra. A idéia principal deste capítulo é

reforçar os conceitos de OO aprendidos com algo mais prático e não

enumerar todos os padrões existentes.

Iremos inicialmente criar um tipo de problema, propondo uma solução ruim.

Iremos dizer o porquê da solução ruim e depois propor uma solução baseada

em algum padrão de projetos.

Entendendo Padrões de Projeto

Antes de começar a mostrar os padrões de projeto, vamos tentar te convencer

a por que usar estes padrões. Muitas pessoas ainda não conseguem enxergar a

utilidade deles, e sofrem depois com manutenção em programas. Vamos

tentar reverter isso, mostrando este exemplo.

Vamos supor que estamos criando pizzas, dado um parâmetro qualquer:

<?xml version="1.0" encoding="utf-8"?>

<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"

xmlns:s="library://ns.adobe.com/flex/spark"

xmlns:mx="library://ns.adobe.com/flex/mx"

minWidth="955" minHeight="600">

<fx:Declarations>

<!-- Place non-visual elements (e.g., services, value

objects) here -->

</fx:Declarations>

<fx:Script>

<![CDATA[

Page 118: Dominando action script3

import mx.collections.ArrayList;

private var pizzas:ArrayList = new

ArrayList(["Calabresa","Presunto","4 Queijos"]);

private var pizza:Pizza;

]]>

</fx:Script>

<s:ComboBox id="combo" dataProvider="{pizzas}">

<s:change>

<![CDATA[

if (combo.selectedItem=="Calabresa")

pizza = new Calabresa();

else if (combo.selectedItem=="Presunto")

pizza = new Presunto();

else if (combo.selectedItem=="4 Queijos")

pizza = new QuatroQueijos();

]]>

</s:change>

</s:ComboBox>

</s:Application>

Neste exemplo (Flex Project), criamos um comboBox com algumas pizzas.

Dependendo do que o usuário escolher (), criamos a pizza. Também temos

as classes que representam uma pizza:

package

{

public class Pizza

{

public function Pizza()

{

}

}

}

package

{

public class Calabresa extends Pizza

{

public function Calabresa()

{

trace("Pizza Calabresa");

}

}

Page 119: Dominando action script3

}

package

{

public class Presunto extends Pizza

{

public function Presunto()

{

trace("Pizza Presunto");

}

}

}

package

{

public class QuatroQueijos extends Pizza

{

public function QuatroQueijos()

{

trace("Quatro Queijos");

}

}

}

Veja que este código está completamente correto. Que está compilando e

funcionando muito bem. O que precisamos entender é que padrões de

projeto foram criados para criamos programas dos quais podemos dar

manutenção. O código acima parece correto porque o programa está

pequeno, muito pequeno.

Imagine agora a seguinte situação: O seu programa está completo, você tem

1000 linhas de código, tudo funcionando. Você usou a abordagem acima, ou

seja, criou as pizzas no evento change do comboBox.

Agora veja esta nova situação:

Além do combobox, em uma segunda feira qualquer, o seu chefe pediu para

colocar uma caixa de texto onde o vendedor pode inserir um código e assim

criar a pizza. Nesse ponto, você está na pressão, tem que entregar

funcionando hoje, e faz o seguinte:

<s:TextInput id="caixaTexto" width="100" top="30">

<s:keyDown>

<![CDATA[

if (caixaTexto.text=="1")

pizza = new Calabresa();

Page 120: Dominando action script3

else if (caixaTexto.text=="2")

pizza = new Presunto();

else if (caixaTexto.text=="3")

pizza = new QuatroQueijos();

]]>

</s:keyDown>

</s:TextInput>

<s:ComboBox id="combo" dataProvider="{pizzas}">

<s:change>

<![CDATA[

if (combo.selectedItem=="Calabresa")

pizza = new Calabresa();

else if (combo.selectedItem=="Presunto")

pizza = new Presunto();

else if (combo.selectedItem=="4 Queijos")

pizza = new QuatroQueijos();

]]>

</s:change>

</s:ComboBox>

Aqui começam os problemas. O primeiro ato desesperado de um

programador é copiar e colar o código, e isso é a pior coisa que ele pode fazer

na vida. Porque? Por que quando formos adicionar uma nova pizza, teremos

que alterar em dois lugares diferentes. Não existe nada pior que isso. No

código acima pode até parecer fácil, mas quando temos um código muito

extenso, com umas 1000 linhas separando cada função, certamente você vai

alterar em um lugar e não vai alterar em outro. Imagine quando existem

códigos clonados em dois arquivos diferentes. Resultado: seu chefe te liga

dizendo que o combobox está criando a nova pizza, mas a caixa de texto não.

Melhorando um pouco esta solução, e acredito que você vai querer melhorá-

la, vamos criar um método que contém todos esses IFs. Veja:

<fx:Script>

<![CDATA[

import mx.collections.ArrayList;

private var pizzas:ArrayList = new

ArrayList(["Calabresa","Presunto","4 Queijos"]);

private var pizza:Pizza;

private function CreatePizza(tipo:String):void

Page 121: Dominando action script3

{

if (tipo=="Calabresa" || tipo == "1")

pizza = new Calabresa();

else if (tipo=="Presunto" || tipo =="2")

pizza = new Presunto();

else if (tipo=="4 Queijos" || tipo == "3")

pizza = new QuatroQueijos();

}

]]>

</fx:Script>

<s:TextInput id="caixaTexto" width="100" top="30">

<s:keyDown>

<![CDATA[

CreatePizza(caixaTexto.text);

]]>

</s:keyDown>

</s:TextInput>

<s:ComboBox id="combo" dataProvider="{pizzas}">

<s:change>

<![CDATA[

CreatePizza(combo.selectedItem);

]]>

</s:change>

</s:ComboBox>

Agora sim, você centralizou tudo em uma função. Então você acredita que

melhorou muito o código e vai pra casa feliz! Dois meses depois, seu chefe

chega em uma manhã de segunda feira e diz: “Sabe aquele programa de

pizzas? Agora coloca pra mim a pizza de chocolate”. Aqui surge outro grande

problema e é justamente aqui que entra os padrões de projeto. Nós somos

seres humanos, e não máquinas. A primeira coisa que irá pensar enquanto

carrega o programa de pizzas é: “onde mesmo que eu coloquei a função que

cria pizzas????”. E vai levar um bom tempo para achá-la, e adicionar a nova

pizza. Ok, você levou um tempo para adicionar a pizza no método

CreatePizza. Agora você precisa criar a classe Chocolate, que herda de pizza.

“Nossa!! - você diz – Isso foi muito fácil. Eu fui no package pizzas e só criei

a classe!!”.

Page 122: Dominando action script3

Viu a diferença entre criar uma nova classe e alterar uma classe existente?

Muitos padrões de projeto são baseados nisso, em criar novas coisas ao invés

de alterar coisas existentes.

Aliás criar ao invés de alterar é uma boa metodologia OO chamada: Open Closed Principle. Se você está gostando de Design Patterns poder ler este link após terminar de ler o livro: http://butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod

Agora vamos dar um jeito no programa de Pizzas!!

Factory

A palavra Factory sozinha não quer dizer nenhum padrão de projetos.

Existem dois principais padrões (Abstract Factory e Factory Method) que

usam este conceito e são os padrões mais utilizados. Antes de abordá-los

temos que compreender o que é um Factory. Em inglês, factory quer dizer

fábrica e conceitualmente falando, uma fábrica cria alguma coisa.

Então o padrão que tem o Factory no nome, é responsável em criar algo. No

programa de pizzas podemos usar um Factory para criar as pizzas, veja:

<fx:Script>

<![CDATA[

import mx.collections.ArrayList;

private var pizzas:ArrayList = new

ArrayList(["Calabresa","Presunto","4 Queijos"]);

private var pizza:Pizza;

private function CreatePizza(tipo:String):void

{

pizza = PizzaFactory.CreatePizza(tipo);

}

]]>

E a classe PizzaFactory:

package

{

public class PizzaFactory

{

Page 123: Dominando action script3

public function PizzaFactory()

{

}

public static function CreatePizza(tipo:String):Pizza

{

if (tipo=="Calabresa" || tipo == "1")

return new Calabresa();

else if (tipo=="Presunto" || tipo =="2")

return new Presunto();

else if (tipo=="4 Queijos" || tipo == "3")

return new QuatroQueijos();

return null;

}

}

Ok, agora você deve estar imaginando: “Ah, você somente „empurrou‟ um

método para uma classe...”. A minha resposta é: sim, eu fiz isso. Mas por

quê? Por que estamos criando um padrão (Lembre-se, estamos estudando

padrões de projeto), e a partir de agora, em qualquer parte do programa,

sempre que eu quiser criar objetos dado alguma característica, vamos usar

uma classe Factory.

Factory Method

Ah, e parabéns, você acabou de aprender seu primeiro padrão de projetos,

chamado Factory method. Ele é usado sempre que criamos classes mas não

sabemos ao certo qual classe criar, porque existem parâmetros a serem

passados.

Agora, quando o seu chefe pedir para criar uma nova pizza, você já sabe:

tenho que encontrar a classe PizzaFactory.

Voltando ao projeto das Pizzas, nós ainda temos um problema. Inicialmente

estamos preenchendo o ComboBox manualmente. Ou seja, para adicionar

uma nova pizza nós temos que abrir o arquivo mxml e preencher mais um

Page 124: Dominando action script3

item. Certamente você não lembrará disso, quando for adicionar uma nova

Pizza. Então para resolver este problema, podemos melhorar o nosso Factory:

package

{

import flash.utils.describeType;

import flash.utils.getDefinitionByName;

import mx.collections.ArrayList;

import mx.core.ClassFactory;

public class PizzaFactory

{

public function PizzaFactory()

{

}

private static function configurePizzas():ArrayList

{

var pizzas:ArrayList = new ArrayList();

pizzas.addItem(new Calabresa());

pizzas.addItem(new Presunto());

pizzas.addItem(new QuatroQueijos());

return pizzas;

}

public static function GetPizzasName():ArrayList

{

var pizzasName:ArrayList = new ArrayList();

var pizzas:ArrayList =

PizzaFactory.configurePizzas();

for each (var pizza:Pizza in pizzas.source)

{

pizzasName.addItem(pizza.Name);

}

return pizzasName;

}

public static function CreatePizza(tipo:String):Pizza

{

var pizzas:ArrayList =

PizzaFactory.configurePizzas();

var newPizza:Pizza;

Page 125: Dominando action script3

for each (var pizza:Pizza in pizzas.source)

{

if (tipo == pizza.Name || tipo ==

pizza.Codigo)

{

var reflection : XML =

describeType(pizza);

var classToInstantiate : Class =

getDefinitionByName(reflection.@name) as Class;

var myClassFactory : ClassFactory =

new ClassFactory(classToInstantiate);

var myObjectInstance :Pizza =

myClassFactory.newInstance();

return myObjectInstance;

}

}

return null;

}

}

}

Agora, a nossa PizzaFactory está completa. O método configurePizzas, em

, é responsável em configurar quais as Pizzas estão disponíveis no sistema.

Veja que esse método é estático, para que possamos chamar o método com

mais facilidade do mxml principal (ou de outro lugar).

O uso de métodos estáticos é comum nesse padrão, a perda de performance é

muito pequena em relação a um método normal e o ganho de produtividade

compensa a perda de processamento.

Veja que, em , estamos adicionando uma instância da classe Calabresa a

um array de pizzas. Em , criamos o método GetPizzasName, que é

responsável em obter as pizzas configuradas e retornar um array contendo o

nome de cada uma das pizzas.

O método CreatePizza não usa mais if/else if para retornar a instância correta

da classe. Agora usamos o método configurePizzas para obter as pizzas que

estão cadastradas, e em fazemos um for para verificarmos, uma a uma, se

o nome ou código fornecido são válidos. Quando acharmos a pizza escolhida,

Page 126: Dominando action script3

iniciamos uma seqüência de códigos em na qual chamamos de reflection,

muito usada em linguagens como Java e C#, com o propósito de criar a

instância de uma classe de forma dinâmica. Com isso não precisamos fazer,

por exemplo, o new Calabresa(), pois é feito automaticamente.

Dica: Gostou de reflection? Você pode ver mais neste link: http://flexiblegorilla.com/wordpress/?p=140

Em , retornamos a instância do objeto, no qual podemos usá-lo da forma

que quisermos.

O código principal ficou extremamente simples, veja:

<?xml version="1.0" encoding="utf-8"?>

<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"

xmlns:s="library://ns.adobe.com/flex/spark"

xmlns:mx="library://ns.adobe.com/flex/mx"

minWidth="955" minHeight="600">

<fx:Declarations>

<!-- Place non-visual elements (e.g., services,

value objects) here -->

</fx:Declarations>

<fx:Script>

<![CDATA[

private var pizza:Pizza;

]]>

</fx:Script>

<s:TextInput id="caixaTexto" width="100" top="30">

<s:keyDown>

<![CDATA[

PizzaFactory.CreatePizza(caixaTexto.text);

]]>

</s:keyDown>

</s:TextInput>

<s:ComboBox id="combo"

dataProvider="{PizzaFactory.GetPizzasName()}">

<s:change>

<![CDATA[

PizzaFactory.CreatePizza(combo.selectedItem);

]]>

Page 127: Dominando action script3

</s:change>

</s:ComboBox>

</s:Application>

Repare que o combo usa o Factory para obter a lista de pizzas e usa o

Factory para obter uma instância da pizza selecionada.

Agora, quando o seu chefe pedir para adicionar mais uma pizza no sistema,

você irá pensar: “Eu usei neste sistema o padrão Factory, que possui fábricas

para criar e manipular objetos. Então eu tenho que criar uma nova classe que

herda de pizza e depois acessar método configure da PizzaFactory para

adicionar essa nova classe na minha lista de pizzas”.

Abstract Factory

O padrão abstract factory é uma extensão ao Factory Method. O Abstract

Factory encapsula vários factories que possuem alguma relação. Agora que

você já conhece o padrão factory, pode, por exemplo, criar um conjunto de

classes relativo ao uso de ingredientes.

Mas antes de começarmos a codificar, vamos esclarecer um ponto importante

sobre OO e sobre o Action Script 3.0. No mundo OO existe um tipo de classe

chamado “classe abstrata”. Até o padrão Abstact Factory é relacionado a

essas classes.

Por definição, uma classe abstrata é uma classe que não pode ser instanciada,

e cujo os seus métodos podem ser reutilizados pelas classes filhas. Quando

discutíamos sobre OO, ensinamos a sempre comparar nossas classes com o

mundo real. Fazendo essa comparação, descobrimos que ninguém quer comer

uma pizza vazia, com apenas a massa e sem recheio. Com isso deduzimos

que não poderíamos, a princípio, criar uma classe Pizza (new Pizza() ). Isso

sugere fortemente que a classe Pizza é abstrata.

Mas então encontramos um problema. No Action Script 3.0, não existe o

conceito de classe abstrata, e para termos uma classe com um comportamento

um pouco semelhante à classe abstrata, precisamos de certa forma programar

Page 128: Dominando action script3

mais um pouco. Este tipo de programação não é o foco desta obra, pois

estamos apenas mostrando algumas particularidades dos padrões de projeto

na linguagem Action Script 3.0.

Singleton

Este padrão é bastante conhecido pelos usuários Java e C#. Em teoria, este

padrão diz que uma classe deve somente possuir uma instância durante todo o

sistema. Você pode pensar: “isso é uma variável global!!”. Os conceitos

realmente são muito semelhantes, mas o uso de Singleton é mil vezes melhor

do que usar variáveis globais.

Aliás, o Flex possui dezenas de classes Singleton, e talvez você já tenha

utilizados sem saber. Na maioria dos casos, as classes Singleton terminam

com a palavra Manager – uma convenção da Adobe. Por exemplo, a classe

PopUpManager que é responsável em adicionar janelas PopUp no Flex é uma

classe singleton.

Criar uma classe singleton com Java ou C# é eventualmente simples. Existe

uma “receita de bolo” para isso, e iremos usá-la aqui. Para criamos uma

classe Singleton, podemos usar o seguinte código:

class MySingleton

{

private static var _instance: MySingleton;

public function MySingleton ( ) { }

public static function getInstance( ): MySingleton

{

if (_instance == null) {

MySingleton. _instance = new MySingleton ( );

}

return MySingleton._instance;

Page 129: Dominando action script3

}

}

Uma das poucas diferenças desta receita é o uso do public no método

construtor da classe. Teoricamente uma classe Singleton não pode ser

instanciada, então o método construtor deveria ser private, mas o Action

Script 3.0 não permite isso.

Vamos a um exemplo prático. Suponha que no seu sistema você queria

controlar o usuário logado nele. Esse usuário é representado por uma classe

que contém os seus dados (Usuario.as) e outra classe que contém o padrão

Singleton, chamada de UsuarioManager (seguindo o padrão do Flex).

package

{

public class Usuario

{

public var Nome:String;

public var Email:String;

public function Usuario()

{

}

}

}

e:

package

{

public class UsuarioManager

{

private static var _instance:UsuarioManager;

public var UsuarioLogado:Usuario;

public function UsuarioManager()

{

}

public static function

getInstance():UsuarioManager

{

if (_instance == null)

_instance = new UsuarioManager();

Page 130: Dominando action script3

return _instance;

}

}

}

Analisando a classe UsuarioManager, percebemos que a sua estrutura é

parecida com a receita de bolo do padrão Singleton.Temos um método

chamado getInstance() que retorna a instância do UsuárioManager. Na

primeira vez que getInstace() é chamado, a variável _instance é instanciada e

a partir deste momento, ela é sempre usada independente de onde é chamada.

No exemplo a seguir, criamos uma analogia a uma tela de login. Suponha que

assim que o usuário efetuar o login no sistema, preenchemos a variável

UsuárioLogado do UsuarioManager.

Na aplicação principal temos:

<?xml version="1.0" encoding="utf-8"?>

<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"

xmlns:s="library://ns.adobe.com/flex/spark"

xmlns:mx="library://ns.adobe.com/flex/mx"

minWidth="955" minHeight="600">

<fx:Script>

<![CDATA[

import mx.managers.PopUpManager;

]]>

</fx:Script>

<fx:Declarations>

<!-- Place non-visual elements (e.g., services, value

objects) here -->

</fx:Declarations>

<s:creationComplete>

<![CDATA[

//Faz de conta que o usuário acabou de logar....

var u:Usuario = new Usuario();

u.Nome = "Daniel";

u.Email = "[email protected]";

UsuarioManager.getInstance().UsuarioLogado = u;

//Adicionamos um Popup !!

var popup:MyPopUp = new MyPopUp();

PopUpManager.addPopUp(popup,this);

Page 131: Dominando action script3

]]>

</s:creationComplete>

</s:Application>

Veja que em , no evento creationComplete da aplicação, criamos um objeto

da classe Uauário, e atribuímos este objeto a propriedade UsuarioLogado do

UsuarioManager (). Em , criamos um popup, que abre um outro

componente mxml. Neste componente, usamos o padrão Singleton para obter

a classe UsuarioManager e usarmos algumas propriedades da classe:

<?xml version="1.0" encoding="utf-8"?>

<s:Panel xmlns:fx="http://ns.adobe.com/mxml/2009"

xmlns:s="library://ns.adobe.com/flex/spark"

xmlns:mx="library://ns.adobe.com/flex/mx"

width="400" height="300">

<fx:Declarations>

<!-- Place non-visual elements (e.g., services,

value objects) here -->

</fx:Declarations>

<s:creationComplete>

<![CDATA[

this.title = "Olá " +

UsuarioManager.getInstance().UsuarioLogado.Nome;

]]>

</s:creationComplete>

</s:Panel>

Retirando o getInstance()

Na verdade não podemos simplesmente retirar a chama ao método

getInstance(), mas podemos escondê-la do usuário final e implementá-la

dentro da classe UsuarioManager, conforme a refatoração a seguir:

package

{

public class UsuarioManager

{

private static var _instance:UsuarioManager;

public var UsuarioLogado:Usuario;

public function UsuarioManager()

Page 132: Dominando action script3

{

}

protected static function

getInstance():UsuarioManager

{

if (_instance == null)

_instance = new UsuarioManager();

return _instance;

}

public static function getUsurario():Usuario

{

return getInstance().UsuarioLogado;

}

public static function

setUsuarior(_usuario:Usuario):void

{

getInstance().UsuarioLogado = _usuario;

}

public static function isLogged():Boolean

{

return getInstance().UsuarioLogado != null;

}

}

}

Veja que o método getInstance() continua o mesmo, exceto pela mudança de

public para protected. Assim, o método não é visto por quem estiver usando a

classe UsuarioManager. Os outros métodos, como o getUsuario(), são

públicos e usam o getInstance() internamente ().

Assim, os métodos surgem para o usuário na complementação de código no

próprio FlashBuilder, como na figura a seguir:

Page 133: Dominando action script3

O uso do Singleton é um grande aliado na melhoria de código. A dica é

NUNCA usar parentAplication em sua aplicação. Se você não sabe o que é

parentAplication, é melhor não saber mesmo.

Observer

O padrão Observer é bastante usado no framework Flex, em diversas partes

do código, como nos eventos e databinds existentes. O próprio databind de

um componente faz com que o uso do padrão Observer seja reduzido, mais

ainda existe muitas aplicações para ele.

Este padrão é formado de uma interface chamada Observer, e de uma outra

classe que se registra no observador. O padrão possui um método qualquer,

que através de um for each dispara alguma coisa na classe registradora dado

algum acontecimento.

Vamos a um exemplo prático para podermos entender melhor o processo.

Suponha que em uma aplicação capaz de pegar botões na tela e embaralhar

Page 134: Dominando action script3

eles (alterar o x e y). Existem dois jeitos de fazer isso. O primeiro, mostrado a

seguir, não usamos nenhum padrão e temos que fazer quase tudo na mão,

veja:

<?xml version="1.0" encoding="utf-8"?>

<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"

xmlns:s="library://ns.adobe.com/flex/spark"

xmlns:mx="library://ns.adobe.com/flex/mx"

minWidth="955" minHeight="600">

<fx:Script>

<![CDATA[

import spark.components.Button;

]]>

</fx:Script>

<fx:Declarations>

<!-- Place non-visual elements (e.g., services,

value objects) here -->

</fx:Declarations>

<s:creationComplete>

<![CDATA[

for (var i:int = 0;i<10;i++)

{

var b:Button = new Button();

b.label = i.toString();

b.x = Math.random() * 300;

b.y = Math.random() * 300;

this.addElement(b);

}

]]>

</s:creationComplete>

<s:Button label="De novo!">

<s:click>

<![CDATA[

for (var i:int = 0;i<10;i++)

{

var b:Button = getElementAt(i) as

Button;

b.x = Math.random() * 300;

b.y = Math.random() * 300;

}

]]>

</s:click>

</s:Button>

Page 135: Dominando action script3

</s:Application>

Neste código, criamos em um for um conjunto de botões com x e y

randômicos. Criamos também o botão “De novo”, que repete o código para

alterar X e Y. Nós podemos melhorar muito esse código, mesmo sem usar

padrões. Por exemplo, poderíamos criar uma função que altera os valores

randomicamente e poderíamos criar uma variável que contém o número de

botões que serão inseridos na tela.

Estas soluções melhoram o código, mas esbarram no problema da

manutenção. Suponha que daqui a dois meses você precise alterar a

quantidade de botões na tela. Se for um programa muito grande, você vai

demorar um pouco para encontrar a variável que diz essa quantidade.

Suponha que agora o programa é em 3D e existe a variável Z. Onde mesmo

que está a função que embaralha as coordenadas? Tudo isso causa transtornos

na manutenção de código e podemos usar padrões para resolver o problema.

O padrão de projetos observer faz com que criemos um observador e

colocamos algumas classes registradas nesse observador. Então o observador

tem a habilidade de notificar essas classes quando quiser.

Vamos inicialmente criar duas interfaces:

package

{

public interface IObserver

{

function notify():void;

}

}

e:

package

{

public interface IRegister

{

function add(o:IObserver):void;

function notifyAll():void;

Page 136: Dominando action script3

}

}

Estas duas interfaces são o esqueleto básico do padrão observer. Dessa

forma, podemos usá-la em qualquer lugar dentro da aplicação, sempre

aproveitando o “esqueleto” da interface (você pode trocar a palavra esqueleto

por contrato, caso fique mais fácil de entender).

Agora vamos criar as classes que implementam estas interfaces. Vamos

chamá-las de ButtonRegister e ButtonObserver. Use o FlashBuilder para criar

a classe e certifique-se de adicionar a interface correta no assistente.

package

{

public class ButtonObserver implements IObserver

{

public function

ButtonObserver(container:SkinnableContainer, label:String)

{

}

public function notify():void

{

}

}

}

Inicialmente ButtonObserver apenas traz os métodos que devemos

implementar. O mesmo acontece com o ButtonRegister:

package

{

public class ButtonRegister implements IRegister

{

public function ButtonRegister()

{

}

public function add(o:IObserver):void

{

}

Page 137: Dominando action script3

public function notifyAll():void

{

}

}

}

Agora vamos implementar cada classe. O ButtonObserver precisa adicionar

um botão na tela e também precisa do código para embaralhar as

coordenadas:

package

{

import spark.components.Button;

import spark.components.SkinnableContainer;

public class ButtonObserver implements IObserver

{

protected var _Button:Button;

public function ButtonObserver(

container:SkinnableContainer, label:String)

{

_Button = new Button();

_Button.label = label;

container.addElement(_Button);

notify();

}

public function notify():void

{

this._Button.x = Math.random()*300;

this._Button.y = Math.random()*300;

}

}

}

Veja que criamos um Spark Button e adicionamos ele ao container. Em

notify, alteramos a propriedade x e y do botão.

Veja que agora o ButtonObserver altera as propriedades do botão. No nosso

primeiro exemplo, quem fazia isso era a aplicação principal. E isso é muito

ruim, muito ruim mesmo, porque quando formos dar manutenção, ficaríamos

um bom tempo tentando achar a função que muda o x e y do botão. Quando

temos o padrão observer, sabemos que somente o observer pode alterar as

Page 138: Dominando action script3

propriedades relacionadas ao que se deseja fazer, então é mais fácil aplicar

uma manutenção no futuro.

Agora vamos analisar a implementação da classe ButtonRegister:

package

{

import mx.collections.ArrayList;

public class ButtonRegister implements IRegister

{

protected var buttons:ArrayList;

public function ButtonRegister()

{

buttons = new ArrayList();

}

public function add(o:IObserver):void

{

buttons.addItem(o);

}

public function notifyAll():void

{

for each (var btn:IObserver in

buttons.source)

{

btn.notify();

}

}

}

}

Esta classe possui um Array de IObservers, e é responsável em manter os

observers registrados, e em notificar cada um deles quando preciso, através

do método notifyAll.

Agora com a nossa arquitetura pronta, vamos ao código final:

<?xml version="1.0" encoding="utf-8"?>

<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"

xmlns:s="library://ns.adobe.com/flex/spark"

xmlns:mx="library://ns.adobe.com/flex/mx"

minWidth="955" minHeight="600">

<fx:Script>

Page 139: Dominando action script3

<![CDATA[

import spark.components.Button;

protected var buttonRegister:ButtonRegister;

]]>

</fx:Script>

<s:creationComplete>

<![CDATA[

buttonRegister = new ButtonRegister();

buttonRegister.add(new ButtonObserver(this,"1"));

buttonRegister.add(new ButtonObserver(this,"2"));

buttonRegister.add(new ButtonObserver(this,"3"));

buttonRegister.add(new ButtonObserver(this,"4"));

]]>

</s:creationComplete>

<s:Button label="De novo">

<s:click>

<![CDATA[

buttonRegister.notifyAll();

]]>

</s:click>

</s:Button>

<fx:Declarations>

<!-- Place non-visual elements (e.g., services,

value objects) here -->

</fx:Declarations>

</s:Application>

No código principal, criamos um único ButtonRegister e adicionamos vários

Observers. O botão “De novo” possui agora uma única chamada, que é o

notifyAll do Register.

Este é apenas um exemplo de como podemos usar o padrão Observer para

realizarmos ações em objetos que implementam a interface IObserver.

Page 140: Dominando action script3

Exemplo real com Observer

Agora vamos aplicar o padrão Observer em um exemplo Real! Suponha que

você tem um formulário, com muitos campos dos mais diversos tipos:

textbox, checkbox, combobox...

Então você precisa implementar um botão para limpar todos os campos do

formulário. No pior caso, esse botão chama um método no qual você limpa os

dados de cada um dos campos, um a um. Talvez essa seja a forma mais

comum usada...

Agora vamos implementar o padrão de projeto Observer nesse problema. Nós

teremos então as seguintes classes:

IObserver e IRegister: São as mesmas classes do exemplo anterior.

Essas classes precisam ser criadas apenas uma única vez. Dica:

Lembra da gLib? Essas classes podem ficar lá e um package

“pattern.observer”.

ClearObserver: É a implementação do observador, que irá “limpar” o

componente

ClearRegister: Contém a lista de objetos para serem “limpados”.

Vamos ao código:

package

{

import mx.core.UIComponent;

import spark.components.CheckBox;

import spark.components.ComboBox;

import spark.components.TextInput;

public class ClearObserver implements IObserver

{

protected var component:UIComponent;

public function ClearObserver

(component:UIComponent)

{

this.component = component;

}

Page 141: Dominando action script3

public function notify():void

{

if (this.component is TextInput)

(this.component as TextInput).text =

"";

else if (this.component is CheckBox)

(this.component as CheckBox).selected

= false;

else if (this.component is ComboBox)

(this.component as

ComboBox).selectedIndex = -1;

/* e mais controles */

}

}

}

e:

package

{

import mx.collections.ArrayList;

public class ClearRegister implements IRegister

{

protected var components:ArrayList;

public function ClearRegister()

{

this.components = new ArrayList();

}

public function add(o:IObserver):void

{

this.components.addItem(o);

}

public function notifyAll():void

{

for each (var component:IObserver in

components.source)

component.notify();

}

}

}

Agora vamos a nossa implementação final, com o formulário:

<?xml version="1.0" encoding="utf-8"?>

<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"

Page 142: Dominando action script3

xmlns:s="library://ns.adobe.com/flex/spark"

xmlns:mx="library://ns.adobe.com/flex/mx"

minWidth="955" minHeight="600">

<fx:Script>

<![CDATA[

protected var clearRegister:ClearRegister;

]]>

</fx:Script>

<s:creationComplete>

<![CDATA[

clearRegister = new ClearRegister();

clearRegister.add(new ClearObserver(txt));

clearRegister.add(new ClearObserver(cmb));

clearRegister.add(new ClearObserver(check));

]]>

</s:creationComplete>

<s:TextInput x="52" y="30" id="txt"/>

<s:ComboBox x="52" y="60" id="cmb"/>

<s:CheckBox x="52" y="91" label="CheckBox" id="check"/>

<s:Button label="Limpar" x="110" y="129">

<s:click>

<![CDATA[

clearRegister.notifyAll();

]]>

</s:click>

</s:Button>

</s:Application>

Execute o programa e veja o comportamento de como o cadastro dos

observadores é executado no notifyAll(). Parece mágica, mas não é !! Desta

forma, você não precisará mais saber como “limpar” cada controle em um

formulário, você apenas precisará adicionar os componentes com o

observador correto, que neste caso é o ClearObserver. Nada impede de você

criar o ValidateObserver e o DefaultObserver, todos responsáveis em realizar

tarefas especificas, mas que estão encapsuladas em seus devidos lugares.

Page 143: Dominando action script3

Para finalizarmos o padrão Observer, analise atentamente as classes

ButtonRegister e ClearRegister. Qual a diferença entre elas? Nenhuma,

apenas mudamos o nome da variável que segura a lista de observadores.

Isso significa que podemos ter um Registrador padrão, e quem determina a

operação a ser realizada é o observador. Com isso, teríamos três classes na

nossa biblioteca gLib: IObserver, IRegister e GenericRegister.

Combinando Padrões (Factory + Observer)

Chegamos ao último capítulo desta obra. Após vermos alguns padrões de

projeto, pudemos analisar como eles podem nos ajudar na manutenção de

código.

Lembre: os padrões de projeto podem nos consumir um pouco mais tempo

para desenvolvermos uma certa arquitetura. Você pode passar alguns minutos

ou horas pensando em qual padrão aplicar para aquele tipo de problema. Mas

assim que você cria e implementa o padrão, tudo fica muito mais fácil.

Para que possamos ter certeza que o padrão aplicado ao problema está bom,

basta olharmos para o resultado e analisarmos se estamos adicionando classes

no sistema ou se estamos alterando classes no sistema. Se a primeira

alternativa está ocorrendo, ou seja, você está adicionando classes e

alimentando arrays de configuração, estás no caminho certo.

Se para adicionar uma funcionalidade no sistema você precise aumentar um if

ou else if , então algo pode ser melhorado e você pode gastar um pouco mais

de tempo com isso.

Se para adicionar uma funcionalidade no sistema você precise alterar vários

arquivos, então .... para tudo! Você está caminhando para um caminho sem

volta, de muita manutenção e estresse!

Bom, após observar estes fatos, vamos novamente olhar um pedaço do nosso

código do padrão Observer:

public function notify():void

Page 144: Dominando action script3

{

if (this.component is TextInput)

(this.component as TextInput).text =

"";

else if (this.component is CheckBox)

(this.component as CheckBox).selected

= false;

else if (this.component is ComboBox)

(this.component as

ComboBox).selectedIndex = -1;

/* e mais controles */

}

Este código pode ser melhorado e podemos transformar estes ifs em um

Factory, assim como aprendemos no capítulo sobre Factory Method.

Agora que estamos unindo dois padrões, é preciso cautela e temos que pensar

um pouco nas classes envolvidas. Como este é um dos exemplos mais

complexos do livro, vamos analisá-lo passo a passo. A seguir vamos ilustrar

as classes que compõem o nosso sistema:

ExemploObserver.mxml: É a aplicação principal do sistema. Nela temos

apenas que informar ao Registrador Genérico os observadores relativos a

limpar campos. O arquivo em si é bastante enxuto, veja:

<?xml version="1.0" encoding="utf-8"?>

<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"

xmlns:s="library://ns.adobe.com/flex/spark"

xmlns:mx="library://ns.adobe.com/flex/mx"

minWidth="955" minHeight="600">

<fx:Script>

<![CDATA[

protected var clearRegister:GenericRegister;

]]>

</fx:Script>

<s:creationComplete>

<![CDATA[

clearRegister = new GenericRegister();

clearRegister.add(new ClearObserver(txt));

//clearRegister.add(new ClearObserver(cmb));

clearRegister.add(new ClearObserver(check));

Page 145: Dominando action script3

]]>

</s:creationComplete>

<s:TextInput x="52" y="30" id="txt"/>

<s:ComboBox x="52" y="60" id="cmb"/>

<s:CheckBox x="52" y="91" label="CheckBox" id="check"/>

<s:Button label="Limpar" x="110" y="129">

<s:click>

<![CDATA[

clearRegister.notifyAll();

]]>

</s:click>

</s:Button>

</s:Application>

A primeira nova classe que vimos aqui é GenericRegister. Discutido no

capítulo anterior, descobrimos que a classe de registro poderia ser genérica, e

implementamos ela neste novo exemplo.

package

{

import mx.collections.ArrayList;

public class GenericRegister implements IRegister

{

protected var observers:ArrayList;

public function GenericRegister()

{

this.observers = new ArrayList();

}

public function add(o:IObserver):void

{

this.observers.addItem(o);

}

public function notifyAll():void

{

for each (var observer:IObserver in

this.observers.source)

observer.notify();

}

}

}

Page 146: Dominando action script3

As classes IRegister e IObserver continuam as mesmas:

package

{

public interface IRegister

{

function add(o:IObserver):void;

function notifyAll():void;

}

}

e

package

{

public interface IObserver

{

function notify():void;

}

}

A classe ClearObserver possui novidades, veja:

package

{

import mx.core.UIComponent;

import spark.components.CheckBox;

import spark.components.ComboBox;

import spark.components.TextInput;

public class ClearObserver implements IObserver

{

protected var myComponent:IComponent;

public function

ClearObserver(component:UIComponent)

{

this.myComponent =

ComponentFactory.createComponent(component);

if (this.myComponent == null)

throw new Error("Não foi possível

encontrar o componente para executar a ação de Clear");

this.myComponent.component = component;

}

Page 147: Dominando action script3

public function notify():void

{

this.myComponent.clear();

}

}

}

No método construtor ClearObserver, usamos um Factory para obtermos o

componente relativo ao componente repassado pelo mxml principal. Aqui

entra a união entre o padrão Observer com o padrão Factory.

Relembrando, o Factory é uma fábrica de objetos, que retorna um objeto

específico dado algum parâmetro. No nosso caso, o parâmetro é o próprio

componente que está no arquivo mxml. Baseado neste parâmetro, retornamos

uma classe que possui funcionalidades ligada àquele componente.

Vamos analisar então o Factory:

package

{

import flash.utils.describeType;

import flash.utils.getDefinitionByName;

import mx.collections.ArrayList;

import mx.core.ClassFactory;

import mx.core.UIComponent;

import myComponents.CheckBox;

import myComponents.TextInput;

public class ComponentFactory

{

public function ComponentFactory()

{

}

public static function getComponents():ArrayList

{

var componentsList:ArrayList = new

ArrayList();

componentsList.addItem(new

myComponents.TextInput());

Page 148: Dominando action script3

componentsList.addItem(new

myComponents.CheckBox());

return componentsList;

}

public static function

createComponent(component:UIComponent):IComponent

{

var reflection:XML =

describeType(component);

for each (var myComponent:IComponent in

getComponents().source)

{

if (myComponent.getParentName() ==

reflection.@name)

{

var reflectionMyComponent:XML =

describeType(myComponent);

var classToInstantiate : Class

= getDefinitionByName(reflectionMyComponent.@name) as

Class;

var myClassFactory :

ClassFactory = new ClassFactory(classToInstantiate);

var myObjectInstance :

IComponent = myClassFactory.newInstance();

return myObjectInstance;

}

}

return null;

}

}

}

Este factory possui dois métodos estáticos. O primeiro deles (), chamado

de getComponents possui o mesmo comportamento do método configure,

visto no capítulo sobre Factory. O objetivo de getComponents é retornar uma

lista de componentes que são da interface IComponent, da qual podemos

realizar operações, como “limpar” o componente.

Vamos analisar a interface IComponent:

package

{

import mx.core.UIComponent;

Page 149: Dominando action script3

public interface IComponent

{

function getParentName():String;

function clear():void;

function get component():UIComponent;

function set

component(component:UIComponent):void;

}

}

A interface diz que precisamos implementar alguns métodos, como

getParentName() e clear(), além de fornecermos uma forma de acessar o

componente da tela. Lembre: Existe o componente da tela e existe a classe

que manipula esse componente, que implementa IComponent.

Por exemplo, criamos o package MyComponents e nele criamos a classe

TextInput. A principal funcionalidade da classe MyComponents.TextInput é

realizar operações no componente spark.components.TextInput. A classe

MyComponents.TextInput é exibida a seguir:

package myComponents

{

import mx.core.UIComponent;

import spark.components.TextInput;

public class TextInput implements IComponent

{

protected var _component:UIComponent;

public function TextInput()

{

}

public function getParentName():String

{

return "spark.components::TextInput";

}

public function clear():void

{

(_component as

spark.components.TextInput).text = "";

}

Page 150: Dominando action script3

public function get component():UIComponent

{

return _component;

}

public function set

component(component:UIComponent):void

{

_component = component;

}

}

}

A classe TextInput que implementa IComponent sempre recebe na variável

set component um componente do tipo TextInput, pois o Factory

ComponentFactory analisa o componente em questão com o método

getParentName().

Para adicionarmos um novo componente, temos que fazer o seguinte:

1) Criar uma classe que implementa IComponent

2) Definir o ParentName, que é o mesmo dos componentes do Flex

3) Adicionar a classe criada no array do método getComponents do

Factory.

Desta forma, podemos até “sofrer” um pouco para entendermos como tudo

funciona em conjunto, mas é garantido que após uma total compreensão de

tudo que está envolvido, podemos nos aproveitar dos padrões de projeto para

beneficiar nossos programas.

É válido lembrar também que esta obra aborda Action Script e não Padrões

de Projeto. Apenas apresentamos alguns (dos muitos existentes) e mostramos

suas soluções usando Action Script 3.0, provando assim que a linguagem é

bastante poderosa e que temos a ferramenta necessária para criarmos

aplicações com os recursos mais avançados sobre OO.

Page 151: Dominando action script3

Para finalizar...

Para finalizar, eu deixo um link muito bom que comenta um pouco mais

sobre OO, e fala de princípios que todo programador deveria conhecer e

seguir. Acesse o link, e continuem seus estudos.

http://butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod