Vamos admitir: Os clientes não têm sido um bom lugar para programadores Java. A tecnologia Java executando nos clientes através de applets, Swing e JavaFX tem sucesso limitado. JavaScript, apesar do nome, não se parece quase nada com a linguagem Java. E o Adobe Flash - bem, é igual ao JavaScript. Ou não? O Flash até podia ser igual ao JavaScript há alguns anos atrás, mas com o advento do ActionScript3, muito foi mudado. E acho que você irá gostar bastante.
Primeiro, ActionScript — a linguagem de programação para Adobe Flex e Flash — tornou-se fortemente tipificada. Também é orientada à objetos, incluindo classes e interfaces. E tem extras que não serão encontradas no Java — especialmente, funções get
e set
para as propriedades e uma extensão de linguagem chamada ECMAScript for XML (E4X), o que torna qualquer documento XML em um objeto que pode ser referenciado através de operadores ponto, como se faz com os objetos regulares.
Este artigo leva você através do básico do ActionScript3 e mostra como ele se compara ao ambiente de desenvolvimento Java a que está acostumado. No final, alguns preconceitos que você tinha a respeito da linguagem serão deixados de lado e poderá se interessar em utilizá-la. Um dos grandes pontos sobre Flex, Flash e ActionScript é que estão disponíveis sem qualquer custo. Simplesmente faça o download do Adobe Flex Builder 3 para começar. Flex Builder, um sofisticado ambiente integrado de desenvolvimento (IDE), não é uma aplicação livre, mas o Flex Software Development Kit (SDK)
Um aviso aos puristas que estão lendo o artigo: Não sou um guru, sendo assim posso deixar passar alguns detalhes da linguagem. Também não estou tentando apresentar tudo sobre ActionScript3 Se é isso o que quer, muitos livros sobre ActionScript3 estão disponíveis. O que posso fazer é introduzir a linguagem. Aqui vamos nós.
Classes e interfaces
Como é com Java, tudo é um objeto em ActionScript3. Existem alguns primitivos como integers, mas além disto tudo é um objeto. Da mesma maneira, existem namespaces e pacotes, como com.jherrington.animals, o que significa o lugar pras as classes empresa / jack herrington / animals, neste caso. É possível colocar as classes no namespace padrão, mas isto não é o mais indicado.
Para definir uma classe, utilize a palavra chave class. Como no exemplo:
package com.jherrington.animals { public class Animal { public function Animal() { } } }
Neste caso defini uma classe Animal
com um construtor que no momento não faz nada.
Posso adicionar variáveis e refinar o construtor facilmente, como é mostrado a seguir:
package com.jherrington.animals { public class Animal { public var name:String = ""; private var age:int = 0; private function Animal( _name:String, _age:int = 30 ) { name = _name; age = _age; } } }
Ali, estou definindo que um objeto Animal
tem duas variáveis; name, que é uma string pública, e age, um inteiro privado. (Aparentemente, animais têm vergonha de suas idades.) O construtor aceita um ou dois valores: apenas a variável name ou name e age. É possível configurar valores padrão para os argumentos adicionando-os na declaração da função.
O que você percebeu neste código é que o tipo da variável está invertido se comparado com o Java. Ali, o tipo vem primeiro; em ActionScript, em segundo. Isto porquê tipificação forte é uma adição recente à linguagem. Assim, para que o suporte ao código antigo, não tipificado, fosse possível, o tipo vem depois do nome da variável.
Vamos estender o exemplo adicionando alguns métodos:
package com.jherrington.animals { import flash.geom.Point; public class Animal { public var name:String = ""; private var age:int = 0; private var location:Point = new Point(0,0); public function Animal( _name:String, _age:int = 30 ) { name = _name; age = _age; } public function moveTo( x:int, y:int ) : void { location.x = x; location.y = y; } public function getLocation( ) : Point { return location; } } }
Como se vê, adicionei outra variável privada, location
, do tipo Point
, que importamos do pacote de geometria do Flash. Também foram adicionados dois métodos que trabalham com location: moveTo
, que movimenta o animal, e getLocation
que retorna o valor atual da variável location.
Agora, esta foi a maneira Java de configurar (set) e verificar (get) um valor. A maneira do ActionScript é muito mais clara, como você pode ver no código a seguir:
package com.jherrington.animals { import flash.geom.Point; public class Animal { public var name:String = ""; private var age:int = 0; private var myLocation:Point = new Point(0,0); public function Animal( _name:String, _age:int = 30 ) { name = _name; age = _age; } public function set location( pt:Point ) : void { myLocation = pt; } public function get location( ) : Point { return myLocation; } } }
Aqui estou usando funções get
e set
que são invocadas quando o código cliente configura ou verifica o valor da variável location
. Para o cliente, a variável location parece ser uma variável normal. Porém você pode introduzir qualquer código que queira para a configuração da variável, bem como também pode fazê-lo para verificá-la.
Como você pode utilizar isto? É possível adicionar um evento que será lançado quando a variável location mudar. Verifique isto no código abaixo:
package com.jherrington.animals { import flash.events.Event; import flash.events.EventDispatcher; import flash.geom.Point; public class Animal extends EventDispatcher { public var name:String = ""; private var age:int = 0; private var myLocation:Point = new Point(0,0); public function Animal( _name:String, _age:int = 30 ) name = _name; age = _age; } public function set location ( pt:Point ) : void { myLocation = pt; dispatchEvent( new Event( Event.CHANGE ) ); } public function get location( ) : Point { return myLocation; } } }
Agora estou especificando que a classe Animal
tem um event dispatcher
- ou seja, um objeto a partir do qual clientes podem ouvir eventos. Então envio um novo evento quando a variável location mudar.
Aqui temos um código cliente que: cria um animal, autoconfigura-se para ouvir eventos de mudança e então, muda o valor de sua variável location:
var a:Animal = new Animal(); a.addEventListener(Event.CHANGE, function( event:Event ) : void { trace( "The animal has moved!" ); } ); a.location = new Point( 10, 20 );
Este código mostra uma mensagem quando o animal for movimentado. É possível definir qualquer tipo de mensagem em ActionScript. A maioria das classes são EventDispatchers e têm eventos para que você adicione ouvintes.
Interfaces
Assim como no Java, ActionScript 3 suporta a construção de interfaces e a implementação destas por classes. A interface mostrada abaixo é um exemplo do quê queremos fazer a partir da classe Animal
:
package com.jherrington.animals { import flash.geom.Point; public interface IAnimal { function get name() : String; function set name( n:String ) : void; function get location() : Point; function set location( pt:Point ) : void; } }
Neste caso estou definindo duas variáveis para a interface, de maneira que possa configurar ou visualizar o valor de ambas. Sim, você pode definir métodos e variáveis em interfaces ActionScript. Como é legal, não?
Para implementá-la fiz algumas mudanças na classe Animal.
Você pode vê-las no código abaixo:
package com.jherrington.animals { import flash.events.Event; import flash.events.EventDispatcher; import flash.geom.Point; public class Animal extends EventDispatcher implements IAnimal { private var myName:String = ""; public function get name() : String { return myName; } public function set name( n:String ) : void { myName = n; dispatchEvent( new Event( Event.CHANGE ) ); } private var myLocation:Point = new Point(0,0); public function set location ( pt:Point ) : void { myLocation = pt; dispatchEvent( new Event( Event.CHANGE ) ); } public function get location( ) : Point { return myLocation; } public function Animal( _name:String ) { name = _name; } } }
É óbvio que posso adicionar variáveis e métodos específicos à esta classe ou implementar outras interfaces além da IAnimal
. Entretanto, assim como em Java, só é possível herdar de uma única classe.
Constantes e estáticos
Action Scripts 3 suporta variáveis tanto constantes quanto estáticas, assim como métodos estáticos. Constantes são fáceis de se definir, como pode ver no código abaixo:
public const MINIMUM_AGE:int = 0; public const MAXIMUM_AGE:int = 2000;
Constantes podem ser definidas com qualquer tipo que se queira, contanto que se faça em tempo de compilação. Também podem estar sob o escopo protected e private.
Para demonstrar uma função estática mostrarei um método de produção da classe Animal
public static function buildAnimal( n:String ) : IAnimal { return new Animal( n ); }
Outra maneira de utilizar um método estático é com o padrão Singleton. Abaixo um exemplo de uma classe factory
Singleton para Animal
package com.jherrington.animals { public class AnimalFactory { private static var _factory:AnimalFactory = new AnimalFactory(); public static function get instance() : AnimalFactory { return _factory; } public function build( n:String ) : Animal { return new Animal( n ); } } }
Para invocá-lo, uso uma variável de instância para acessar o objeto factory
:
private var b:Animal = AnimalFactory.instance.build( "Russell" );
Isto utiliza o objeto factory Singleton para criar um novo animal com o nome Russell.
Herança
Para demonstrar herança mostrarei três interfaces e classes. A primeira interface é a classe IAnimal
acima. A segunda é a classe Animal
e a terceira é uma classe derivada, chamada Dog
que sobrepõe um método.
A interface, IAnimal
, é mostrada abaixo.
public interface IAnimal { function get name() : String; function set name( n:String ) : void; function move( x:int, y:int ) : void; }
Simplifiquei-a um pouco para retornar somente a variável name
e o método move()
. A primeira implementação da interface é a classe Animal
:
public class Animal extends EventDispatcher implements IAnimal { private var myName:String = ""; public function get name() : String { return myName; } public function set name( n:String ) : void { myName = n; dispatchEvent( new Event( Event.CHANGE ) ); } public function Animal( _name:String ) { name = _name; } public virtual function move( x:int, y:int ) : void { } }
Então, a classe Dog
construída sobre a Animal
tem seu construtor e o método move()
sobreposto.
public class Dog extends Animal { public function Dog(_name:String) { super(_name); } public override function move( x:int, y:int ) : void { trace( 'Moving to '+x+', '+y ); } }
Isto é muito parecido com código Java, assim você deve se sentir em caso ao implementar seus códigos ActionScript com orientação à objetos.
Operadores e condicionais
Operadores em ActionScript são exatamente o que se encontra em Java. De modo similar, operadores matemáticos e Booleanos são os mesmos:
var a:int = 5; var b:int = 6; var c:int = a * b; c *= 10; var d:Boolean = ( c > 10 ); var e:int = d ? 10 : 20;
Estes exemplos mostram um pouco dos operadores. A única diferença deste exemplos em ActionScript e Java está na sintaxe para a definição das variáveis.
Como os operadores, os condicionais trabalham exatamente da mesma maneira nas duas linguagens, por exemplo:
if ( a > 10 ) { trace( 'low' ); } else if ( a > 20 ) { trace( 'high' ); } else { threw new Exception( "Strange value" ); }
Mostra ao mesmo tempo a sintaxe dos condicionais e como se lança uma exceção. O controle de exceções é feito da mesma maneira que no Java. É possível criar os seus próprios tipos ou apensa utilizar a classe Exception padrão.
As sintaxes para o try
, catch
e finally
são mostradas a seguir:
try { location = new Point( -10, 10 ); } catch( Exception e ) { trace( e.toString() ); } finally { location = null; }
O código tenta configurar uma localidade e registra um erro caso aconteça um problema. Em qualquer caso, a variável location terá o valor null no final.
Iterators
ActionScript 3 não tem containers fortemente tipificados, mas ainda assim é fácil trabalhar com vetores e tabelas hash. Eis um exemplo da utilização de um loop para percorrer um vetor:
var values:Array = new [ 1, 2, 5 ]; for( var i:int = 0; i < values.length; i++ ) trace( values[i] );
Mas você não escolherá esta maneira para percorrer um vetor em ActionScript. A melhor maneira é utilizar a sintaxe for each, como mostrado no exemplo a seguir:
var values:Array = new [ 1, 2, 5 ]; for each ( var i:int in values ) trace( i );
Este código percorre através de cada elemento do vetor e configura o valor de i para cada um deles enquanto é executado.
Para criar uma tabela hash, você utiliza o tipo básico Object:
var params:Object = { first:'Jack', last:'Herrington' }; for( var key:String in params ) trace( key+' = '+params[key] );
A origem do ActionScript no JavaScript significa que o tipo básico de objeto é um container, baseado em ponto, que pode ser facilmente utilizado como uma tabela hash.
Expressões regulares
São utilizadas de maneira direta na sintaxe básica do ActionScript. Por exemplo, este código:
if ( name.search( /jack/i ) ) { trace('hello jack'); }
faz uma simples verificação em uma string.
Este código utiliza expressões regulares para uma operação de divisão.
var values:String = "1,2,3"; for each( var val:String in values.split(/,/) ) { trace( val ); }
Quando você deve utilizar expressões regulares no seu código é um assunto discutível. Os arquitetos Java obviamente acham que elas devem estar em uma biblioteca externa. Porém, acho que elas são uteis o bastante para estarem integradas ao ActionScript.
E4X
XML é utilizado de maneira ampla o suficiente para que ActionScript tenha suporte para sua construção diretamente em sua sintaxe. Se você é um viciado em XML, irá adorar isto. Verifique:
var myData:XML = <names> <name>Jack</name> <name>Oso</name> <name>Sadie</name> </names>; for each ( var name:XML in myData..name ) { trace( name.toString() ); }
O código define um documento XML e então localiza-o e imprime todas as suas
A próxima porção de código também pega as tags
var myData:XML = <names> <name type="person">Jack</name> <name type="dog">Oso</name> <name type="dog">Sadie</name> </names>; for each ( var name:XML in myData..name.(@type='dog') ) { trace( name.toString() ); }
A sintexe @
é a mesma para o XPath e XSLT. É utilizada para definir que estamos buscando o atributos e não os elementos XML.
E4X é uma fantástica adição à linguagem. Transforma a análise XML em um deleite. Web services podem ser devolvidos em formato E4X para facilitar sua análise.
Conclusão
A Adobe fez avanços extraordinários com ActionScript. É de longe uma linguagem mais sofisticada do que a maioria acredita. Penso que você achará que o que a Adobe fez é ter aprendido algumas lições sobre o que é certo e errado em Java e tê-las incorporado no desenvolvimento do ActionScript. Você ficará feliz como o resultado.
Para maiores informações
- Para mais informações sobre similaridades entre sintaxe Java e ActionScript, leia o artigo de Yakov Fain, "Comparing the syntax of Java 5 and ActionScript 3" (JDJ, November 12, 2006).
- Um conversor Java para ActionScript está disponível, no Open Source Flash, e permite a criação de conteúdo Flash utilizando Java ao invés de ActionScript.
- Para uma lista de recursos que ajudará na migração entre ActionScript, Flex, Java e JavaScript, veja a lista de comparações RIAdobe.
- Flex.org é sua fonte para tudo sobre Adobe Flex.