Oggetti

1. Classi

Passiamo velocemente in rassegna tutte le classi che formeranno la nostra applicazione, a cominciare dagli oggetti di ActionScript 3.


Classi ActionScript 3

Richieste HTTP (Comunicazione con PHP e invio di file)

  • FileReference - Classe principale che utilizzeremo per caricare i file dell'utente sul server e che ci consentirà anche di avere a disposizione e di personalizzare le finestre di dialogo per sfogliare i file dal disco rigido.
  • URLRequest - Classe base per effettuare delle richieste HTTP e comunicare quindi con PHP, la useremo infatti per inviare il file e per controllare che il file sia stato accettato dal server.
  • FileFilter - Utilizzata per impostare dei filtri sui file che l'utente potrà caricare sul server.

Gestione degli Eventi

  • Event - Contiene le costanti base per gestire gli eventi più importanti, come l'avvenuta selezione del file da parte dell'utente o il completamente dell'invio del file sul server.
  • MouseEvent - Usata per gestire gli eventi del mouse (CLICK).
  • IOErrorEvent - Contiene la costante IO_ERROR, utilizzata nel verificarsi di un errore di lettura, scrittura o trasmissione del file, o ancora nel caso in cui il server su cui si tenta di caricare il file richieda un'autenticazione e infine nel caso in cui si tenti di utilizzare un protocollo diverso da HTTP o HTTPS.
  • ProgressEvent - Utilizzeremo questa classe per tenere traccia dello stato di caricamento del file.
  • HTTPStatusEvent - Contiene la costante HTTP_STATUS utilizzata per sollevare eccezioni nel caso in cui si verificasse un errore HTTP.
  • SecurityErrorEvent - Contiene SECURITY_ERROR, inviata quando si verifica una violazione della sicurezza.

Costruzione dell'interfaccia

  • Button - Componente di Flash CS3 che ci consente di inserire dei bottoni standard nel filmato.
  • TextField - Classe per aggiungere campi di testo nello stage.
  • TextFormat - Classe utilizzata per formattare lo stile dei campi di testo TextField.
  • MovieClip - Classe di base per creare il clip filmato con lo stage.

Classi personalizzate

  • Settings - Enumerazione utilizzata per impostare alcuni settaggi base per l'applicazione.
  • PhpService - Classe derivata da EventDispatcher, utilizzata per comunicare più facilmente con i nostri script PHP.

Classi PHP 5

Classi personalizzate

  • UploadSettings - Collezione di costanti utilizzate per configurare il funzionamento dello script.
  • ErroreFile - Derivata da Exception, utilizzata per estendere le eccezioni possibili che possono verificarsi durante l'upload di un file sul server.
  • File - Classe che offre svariati metodi per semplificare la gestione del file inviato e per controllarne il corretto formato.

30. Classi per interrogare PHP

In questo capitolo costruiremo una classe PhpService per inviare e ricevere dati con PHP in codifica URL, derivando la classe da EventDispatcher.
Questo ci consentirà di gestire gli eventi che ci interessano nel nostro script, aggiungendo eventuali listener direttamente alle istanze di PhpService, come mostrato nel capitolo Gestire gli Eventi.

La nostra classe conterrà quattro attributi :

  • private var vars:Array; (Array che conterrà tutte le variabili che saranno inviate allo script PHP in codifica URL)
  • private var script:String; (Stringa che indica il nome della pagina PHP che conterrà lo script di nostro interesse)
  • public var response:URLVariables; (Conterrà i dati restituiti dallo script PHP in seguito alla richiesta HTTP)
  • public static var scriptPath:String; (Variabile statica utilizzata per impostare l'URL di base dove risiedono gli script PHP)

Il costruttore di classe prenderà in input un solo valore che indicherà il nome del file PHP che conterrà lo script di nostro interessa (attributo script).

Prima di dare un'occhiata al codice vediamo quali metodi costituiscono il corpo di classe :

  • public function reset():void
    Azzera l'array di variabili che contiene i dati da inviare allo script PHP.
  • public function addVar(name:String, content:String):void
    Ogni chiamata al metodo aggiunge una variabile all'array di dati che verrà inviato allo script PHP in codifica URL.
    Il metodo prende due parametri : il primo rappresenta il nome della variabile come verrà letta in PHP attraverso l'array globale $_POST[], mentre il secondo rappresenta il valore contenuto nella variabile.
  • public function request():void
    Effettua la richiesta HTTP contattando lo script, inviando e ricevendo i dati con quest'ultimo.
  • public function completeHandler(event:Event):void
    Memorizza la risposta dello script PHP nell'attributo pubblico response e solleva l'evento Event.COMPLETE.

Di seguito riporto il codice del costruttore e dei primi due metodi, molto semplici :

// Costruttore della classe
public function PhpService(PhpScript:String = "default.php"):void
{
	// Memorizza il nome del file PHP che contiene lo script di interesse
	this.script = PhpScript;
	// Inizialliza un array vuoto di variabili per l'invio dei dati allo script PHP
	this.vars = new Array();
}

public function reset():void
{ this.vars = new Array(); }

public function addVar(name:String, content:String):void
{
	/*
	La sintassi che segue permette di inserire nell'elemento di un array
	direttamente un oggetto dinamico con due proprietà "name" e "content"
	*/
	this.vars.push({name: name, content: content});
}

Il prossimo metodo, request, riutilizza il codice visto nel precedente capitolo, con la differenza di una gestione più completa delle variabili che andrà a leggere dall'array vars, per poi trasformarle in codifica URL pronte da inviare allo script PHP.

public function request():void
{
	var urlencoded:String = new String();

	/* Il ciclo "for" che segue, legge gli elementi dell'array vars e li
	trasforma in una stringa con la codifica URL per l'invio allo script PHP */

	for (var i:uint = 0; i < this.vars.length; i++)
	{
		urlencoded += this.vars[i].name + "=" + this.vars[i].content;
		if ((i + 1) < this.vars.length) urlencoded += "&";
	}

	try
	{
		var variables:URLVariables = new URLVariables(urlencoded);

		var loader:URLLoader = new URLLoader();
		loader.dataFormat = URLLoaderDataFormat.VARIABLES;
		loader.addEventListener(Event.COMPLETE, completeHandler);

		var request:URLRequest = new URLRequest(PhpService.scriptPath + this.script);
		request.method = URLRequestMethod.POST;
		request.data = variables;

		loader.load(request);
	}
	catch (error:Error)
	{ trace("Errore di connessione."); }
}

Per ultimo vediamo il metodo completeHandler, il quale memorizzerà la risposta dello script nell'attributo response e solleverà l'evento Event.COMPLETE in modo da poterlo ricatturare e gestire nella classe documento.

private function completeHandler(event:Event):void
{
	var loader:URLLoader = URLLoader(event.target);
	this.response = new URLVariables(loader.data);

	super.dispatchEvent(new Event(Event.COMPLETE));
}

Potete vedere il codice della classe al completo qui.

Di seguito un esempio di classe documento dove viene utilizzata un'istanza di PhpService.

HelloWorld.as

package
{
	import PhpService;
	import flash.events.Event;
	import flash.display.MovieClip;

	public class HelloWorld extends MovieClip
	{
		private var phpserv:PhpService;

		public function HelloWorld():void
		{
			PhpService.scriptPath = "http://localhost/realizzazionesito/";

			this.phpserv = new PhpService("servizio.php");
			this.phpserv.addVar("utente", "mario");
			// this.phpserv.addVar("utente2", "luca");
			// this.phpserv.addVar("utente3", "giovanni");
			this.phpserv.addEventListener(Event.COMPLETE, completeHandler);
			this.phpserv.request();
		}

		private function completeHandler(evt:Event):void
		{
			trace("Return : " + this.phpserv.response);
		}
	}
}

Per la costruzione di una classe più robusta che possa soddisfare i bisogni di un'applicazione reale, vi consiglio di completare il codice di PhpService, aggiungendo la gestione degli eventi che seguono :

addEventListener(Event.COMPLETE, completeHandler); // Questo è già implementato
addEventListener(Event.OPEN, openHandler);
addEventListener(ProgressEvent.PROGRESS, progressHandler);
addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
addEventListener(HTTPStatusEvent.HTTP_STATUS, httpStatusHandler);
addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);

19. Classi Dinamiche e Finali

Classi Dinamiche

Con ActionScript 3 viene introdotto un nuovo concetto applicabile alle nostre classi, che potranno essere sigillate (sealed) oppure dinamiche (dynamic).

Il valore predefinito per tutte le classi è sealed, indicando al compilatore che la classe in esame è sigillata, ossia non vi sarà la possibilità di aggiungere attributi e metodi alla classe in fase di run-time.

Dichiarando invece una classe mediante la direttiva dynamic, avremo la possibilità di aggiungere dei membri ad essa anche al di fuori della sua dichiarazione o in un altro file ActionScript.

Classe Sealed

package
{
	public class MiaClasseSealed
	{ }
}

Classe Dynamic

package
{
	dynamic public class MiaClasseDynamic
	{ }
}

Come potete notare dal codice soprastante, non è necessaria alcuna direttiva per dichiarare una classe come sealed, al contrario per dichiararla dinamica ho anteposto alla dichiarazione della classe il comando dynamic.

Di seguito la classe documento HelloWorld che dichiara ed utilizza due istanze delle classi sopra dichiarate :

package
{
	import MiaClasseSealed;
	import MiaClasseDynamic;

	public class HelloWorld extends MovieClip
	{
		public function HelloWorld():void
		{
			var mySealed:MiaClasseSealed = new MiaClasseSealed();
			var myDynamic:MiaClasseDynamic = new MiaClasseDynamic();

			mySealed.attributo = 10; // Errore
			myDynamic.attributo = 10; // Tutto OK!
		}
	}
}

L'istruzione "mySealed.attributo = 10;" genera il seguente errore poichè la classe è sigillata e non ammette attributi o metodi che non siano stati esplicitamente dichiarati nel corpo della classe :

Accesso a una proprietà non definita attributo mediante un riferimento con tipo statico MiaClasseSealed.


Classi Finali

Abbiamo già dato un'occhiata alle classi finali nel capitolo Costanti ed Enumerazioni, dichiarando quest'ultime come classi finali, a causa del mancato supporto esplicito in ActionScript 3 per questo tipo di costrutti.

Dichiarando una classe come finale, diciamo al compilatore che nessuna classe può ereditare da essa, provocando quindi un errore in fase di compilazione qualora si tentasse di creare un'istanza di una classe che eredita da una classe finale.

Classe base finale

package
{
	public final class ClasseFinale
	{
		// Corpo della classe
	}
}

Classe derivata

package
{
	import ClasseFinale;

	public class Oggetto extends ClasseFinale
	{
		public function Oggetto():void
		{
			trace("Costruttore");
		}
	}
	
}

Provando a creare un'istanza della classe Oggetto otterrete il seguente errore :
La classe base è final.

18. Ereditarietà

L'ereditarietà è uno dei concetti base su cui poggia uno dei paradigmi di programmazione più usati dalle applicazioni moderne, la programmazione orientata agli oggetti, che abbiamo già avuto modo di conoscere nel precedente capitolo sulle classi : Classi

Questo metodo di programmazione ci consente di sfruttare appieno le potenzialità di questo paradigma per i seguenti motivi :

ActionScript 3 ci consente di creare una sottoclasse derivata da un'altra mediante la direttiva extends, come mostrato nell'esempio seguente.

Unita.as - Classe Base

package
{
	public class Unita
	{
		protected var attacco:uint;
		protected var difesa:uint;
		protected var distanza:uint;
		protected var velocita:uint;

		public function Unita():void
		{ /* ... Costruttore ... */ }
	}
}

Fante.as - Classe Derivata

package
{
	import Unita;

	public class Fante extends Unita // "Fante" eredita da "Unita"

	{
		protected var puntiferita:uint;

		public function Fante():void
		{
			this.attacco = 10;
			this.difesa = 20;
			this.distanza = 1;
			this.velocita = 5;

			this.puntiferita = 100;
		}
	}
}

Come possiamo notare dall'esempio soprastante, la classe "Fante" eredita i quattro attributi protected dichiarati nella classe "Unita".
Nota : protected è un modificatore di accesso che restringe la visibilità dei membri alla sola classe base ed alle sue derivate.

Nell'esempio soprastante, abbiamo esteso il codice senza effettuare alcuna modifica alla classe esistente "Unita", ma semplicemente creando una classe specializzata per rappresentare il nuovo tipo di dato "Fante" con un attributo aggiuntivo.

Un altro strumento che l'ereditarietà ci mette a disposizione è la possibilità di ridefinire alcuni elementi delle classi base.

Molti linguaggi ci consentono di ridefinire sia gli attributi che i metodi di una classe, mentre ActionScript 3 ci permette di ridefinire solo i metodi, lasciando tutti gli attributi e le costanti delle classe base (var e const) come proprie di quest'ultima.

E' comunque possibile ridefinire gli attributi attraverso la definizione dei metodi speciali get e set che abbiamo visto nel capitolo precedente.


Ridefinizione dei Metodi

Per ridefinire un metodo in ActionScript 3, si usa la direttiva override seguita dalla dichiarazione del metodo, che dovrà rispecchiare esattamente la struttura del metodo base o il compilatore restituirà il messaggio "Override incompatibile".

Questo significa che se il metodo base prende un determinato numero di parametri di un tipo stabilito, il metodo che andrà a ridefinirlo dovrà prendere gli stessi parametri dello stesso tipo.

Un metodo sarà ridefinibile solo se dichiarato pubblico, protetto o interno.
Se dichiarato privato sarà comunque possibile definire un metodo con lo stesso nome nella classe derivata, in quanto il metodo della classe base non sarà visibile all'esterno (private), e procederemo quindi senza la direttiva override.

Di seguito un semplice esempio dove ridefiniremo il metodo "muovi()" :

Unita.as - Classe Base

package
{
	public class Unita
	{
		protected var attacco:int;
		protected var difesa:int;
		protected var distanza:int;
		protected var velocita:int;

		public function Unita():void
		{ /* ... Costruttore ... */ }

		public function muovi(passi:uint):void
		{
			/* Sposta l'unita di N passi */
			trace("Chiamata a 'Unita.muovi()'");
		}
	}
}

Fante.as - Classe Derivata

package
{
	import Unita;
	
	public class Fante extends Unita
	{
		public function Fante():void
		{
			this.attacco = 10;
			this.difesa = 20;
			this.distanza = 1;
			this.velocita = 5;
		}

		override public function muovi(passi:uint):void
		{
			trace("Chiamata a 'Fante.muovi()'");
		}
	}
}

HelloWorld.as - Classe documento

package
{
	import Fante;
	import flash.display.MovieClip;

	public class HelloWorld extends MovieClip
	{
		public function HelloWorld():void
		{
			var soldato:Fante = new Fante();
			soldato.muovi(10); // Output : Chiamata a 'Fante.muovi()'
		}
	}
}

Se non avessimo effettuato un override nella classe Fante, la chiamata al metodo "muovi()" avrebbe provocato il seguente output :
Chiamata a 'Unita.muovi()'


Metodo super

Potrebbe capitare durante l'implementazione di un override, di non voler riscrivere completamente il metodo base ma di volergli solo aggiungere qualche funzionalità.

In questo caso ci sarà di aiuto lo speciale metodo super, attraverso cui ci sarà possibile accedere direttamente alle proprietà (attributi e metodi) della classe base, da una sua derivata.

Nel prossimo esempio riscriverò solo la classe Fante, lasciando i file Unita.as e HelloWorld.as invariati :

Fante.as - Classe Derivata

package
{
	import Unita;
	
	public class Fante extends Unita
	{
		public function Fante():void
		{
			this.attacco = 10;
			this.difesa = 20;
			this.distanza = 1;
			this.velocita = 5;
		}

		override public function muovi(passi:uint):void
		{
			super.muovi(passi * this.velocita);
			trace("Chiamata a 'Fante.muovi()'");
		}
	}
}

Richiamando la classe documento HelloWorld si ottiene il seguente output :
Chiamata a 'Unita.muovi()'
Chiamata a 'Fante.muovi()'

Nota : vengono ereditati tutti i membri che non sono private e statici.

15. Membri statici


Attributi statici

Fino ad ora abbiamo visto che per utilizzare gli attributi e i metodi di una classe, è necessario creare un'istanza di tale classe, che viene poi usata per richiamare i membri attraverso l'operatore "." (punto).

ActionScript ci consente la gestione di tali attributi e metodi, senza alcuna necessità di allocare un'istanza, dichiarando questi membri come statici, ossia appartenenti solo alla classe e non alle istanze di questa.

Un attributo statico e un metodo statico possono essere paragonati rispettivamente ad una variabile e ad una funzione tradizionali, soggetti però ai vincoli di visibilità imposti dalla classe di appartenenza.

Per accedervi perciò è necessario specificare il nome della classe, seguito dall'operatore di selezione "." (punto).

Questo metodo può tornare utile quando, ad esempio, ci è necessario condividere un valore con tutte le istanze di una classe, e a questo proposito vedremo nell'esempio che segue, una classe DatiLogin che avrà due attributi statici che verranno utilizzati da tutte le istanze della suddetta classe, per verificare che il nome utente e la password usati abbiano una lunghezza minore o uguale alla massima consentita.

DatiLogin.as

package
{
	public class DatiLogin
	{
		// Lunghezza massima per il nome utente di 15 caratteri
		static public var nome_max_length:int = 15;
		// Lunghezza massima per la password utente di 20 caratteri
		static public var pass_max_length:int = 20;

		private var nome_utente:String;
		private var pass_utente:String;

		public function DatiLogin(nome:String, pass:String):void
		{
			if (nome.length <= DatiLogin.nome_max_length) this.nome_utente = nome;
			else throw new Error("Nome utente (" + nome + ") troppo lungo!");

			if (pass.length <= DatiLogin.pass_max_length) this.pass_utente = pass;
			else throw new Error("Password utente (" + nome + ") troppo lunga!");
		}

		public function connetti():void
		{
			/* Si connette ad un server utilizzando
			nome_utente e pass_utente per autenticarsi */
		}
	}
}

La classe dell'esempio soprastante è stata scritta per uno scopo puramente didattico.

Di seguito un esempio che mostra un uso ipotetico della classe DatiLogin.

HelloWorld.as

package
{
	import DatiLogin;
	import flash.display.MovieClip;

	public class HelloWorld extends MovieClip
	{
		public function HelloWorld():void
		{
			/* Reimpostiamo la lunghezza massima
			per il nome utente fino a 20 caratteri */
			DatiLogin.nome_max_length = 4;

			var loginSito1:DatiLogin = new DatiLogin("root", "cicciobello"); // Ok
			var loginSito2:DatiLogin = new DatiLogin("admin", "pippopluto"); // Errore
		}
	}
}

L'inizializzazione dell'istanza loginSito2 provoca un errore, perchè il nome utente "admin" è di 5 caratteri, mentre il massimo consentito è stato impostato a 4 attraverso la variabile statica "nome_max_length".

Ricordate che non potrete accedere ai membri statici attraverso le istanze, e neppure attraverso this dall'interno della classe, ma solo specificando il nome della classe come abbiamo visto nell'esempio precedente.

var login:DatiLogin = new DatiLogin("root", "password");

login.nome_max_length = 15; // Errore, operazione non consentita
DatiLogin.nome_max_length = 15; // Tutto Ok!

Metodi statici

Come ho anticipiato all'inizio, i metodi statici sono come delle funzioni tradizionali, ma vincolate dalle regole di visibilità ed accessibilità imposte dalla classe a cui appartengono.

Può essere necessario implementare un metodo statico in una classe, per fornire ad esempio un pseudo-costruttore che invece di inizializzare un nuovo oggetto, restituisce un'istanza di questa classe inizializzata a partire da un file XML esterno.

Segue una bozza di una classe d'esempio "Salvataggio", che disporrà di un metodo statico per caricare i salvataggi da un file esterno in formato XML.


Salvataggio.as

package
{
	public class Salvataggio
	{
		var partita:*;
		var data:Date;
		var giocatore:String;

		public function Salvataggio():void
		{
			// ...
		}

		static public function caricaDaXML(nome_file:String):Salvataggio
		{
			var save:Salvataggio = new Salvataggio();

			/* Apre e legge un file XML con i dati di gioco ed
			inizializza un'istanza di "Salvataggio" con questi dati */

			return save;
		}
	}
}

HelloWorld.as

package
{
	import Salvataggio;
	import flash.display.MovieClip;

	public class HelloWorld extends MovieClip
	{
		public function HelloWorld():void
		{
			var save:Salvataggio = Salvataggio.caricaDaXML("mario_01_save.xml");
		}
	}
}

Infine, i membri statici, non vengono eriditati dalle sottoclassi.

14. Classi

Teoria sulle classi

Questo è senzaltro uno dei capitoli essenziali della presente guida, dal momento che ActionScript 3 si è evoluto, rispetto ai suoi predecessori, basandosi fortemente sulla programmazione orientata agli oggetti (OOP).

La programmazione orientata agli oggetti è un metodo di sviluppo ormai molto diffuso, poichè consente di risparmiare molto tempo rendendo la scrittura del codice più intuitiva e l\'applicazione più robusta, accorciando le distanze fra la cruda programmazione e il mondo reale.

In linea di massima e limitando molto il concetto, possiamo pensare ad un oggetto semplicemente come ad un nuovo tipo di dato creato da noi, con particolari attributi e metodi per gestirlo.

Immaginiamo ora di dover scrivere un\'applicazione che disegna sullo stage un triangolo.
Per disegnare il triangolo innanzitutto ci saranno necessarie le coordinate dei suoi punti, ed essendo un triangolo ne avrà tre.

Con le nozioni apprese fino ad ora potremmo memorizzare questi dati all'interno di varibili o ancora meglio all'interno di un array.
Avendo ogni punto due coordinate (x e y) sarà quindi necessario un array di 6 elementi come mostrato di seguito :

function disegnaTriangolo(triangolo:Array):void
{ /* Codice per disegnare il triangolo */ }

var triangolo:Array = new Array();

triangolo["x1"] = 5;
triangolo["y1"] = 10;
triangolo["x2"] = 30;
triangolo["y2"] = 40;
triangolo["x3"] = 70;
triangolo["y3"] = 90;

disegnaTriangolo(triangolo);

L'esempio soprastante non è certo il migliore dei modi per gestire il problema proposto, soprattutto se supponiamo di dover disegnare molti triangoli, il codice diventerebbe allora una lunga e pesante matassa di assegnazioni.

Iniziamo a dare una sfoltita al codice immaginando di poter creare il nuovo tipo di dato Punto.
Assieme a questa nuova classe potremmo, ad esempio, creare ancora un nuovo tipo che chiameremo Triangolo, che avrà al suo interno tre variabili del tipo Punto.

Il codice si presenterebbe così :

var triangolo1:Triangolo = new Triangolo(new Punto(5, 10), new Punto(30, 40), new Punto(70, 90));
triangolo.disegna();

Il sorgente non è solo più pulito e intuitivo, ma il codice per definire le classi Punto e Triangolo, sarà universale e potrete utilizzarlo per tutte le vostre applicazioni senza alcuna necessità di riscriverlo.

I vantaggi che potrete trarre da questo metodo di programmazione sono innumerevoli, e vi saranno tutti molto più chiari man mano che andrete avanti con la lettura, imparando a pensare alle vostre applicazioni direttamente come ad una serie di oggetti in relazione fra loro.


Le classi in ActionScript 3

Le classi in ActionScript 3 devono avere obbligatoriamente un package di appartenenza, concetto che illustrerò più avanti, intendendo per ora i package come dei semplici contenitori di classi.

Le classi dovranno essere scritte in file esterni con estensione .as.
Per farlo è sufficiente aprire il Blocco note e salvare i file con l'estensione specificata pocanzi, oppure tramite Flash CS3 creando un nuovo File ActionScript (CTRL + N).

Per dichiarare una classe abbiamo a disposizione l'istruzione class :

package
{
	public class MiaClasse
	{
		// Corpo della classe
	}
}

La parola chiave public è un modificatore di accesso, ed indica che la classe è accessibile anche dall'esterno.

A questo punto per poter continuare a illustrare le classi, è necessario introdurre alcuni nuovi concetti.

Le classi non definiscono un tipo di dato comune, e per inizializzare correttamente la variabile che dovrà contenere il nostro oggetto, è necessaria l'istruzione new, già vista in qualche esempio precedente.

La variabile che conterrà l'oggetto è detta istanza.

var contenitore:MiaClasse = new MiaClasse();

Nell'esempio soprastante, "contenitore" è un'istanza della classe "MiaClasse".

Una classe può definire degli attributi e dei metodi, che sarà possibile richiamare attraverso un'istanza seguita dall'operatore di selezione ".".

Potete pensare agli attributi (detti anche proprietà) come a delle variabili proprie dell'oggetto, e potete pensare ai metodi come a delle funzioni proprie dell'oggetto.

Vediamo un esempio in cui dichiaro una classe Punto con due attributi x e y e un metodo output :

package
{
	public class Punto
	{
		var x:Number; // Attributo
		var y:Number; // Attributo

		function output():void // Metodo
		{
			trace("x = " + this.x);
			trace("y = " + this.y);
		}
	}
}

In questo frammento di codice possiamo osservare una nuova istruzione : this.
this è una sorta di puntatore che ci consente di accedere agli attributi e ai metodi della classe, dall'interno di quest'ultima.

Vediamo ora il codice che ci permetterà di utilizzare la classe inizializzandone un'istanza, e accedendo agli attributi mediante essa.

var p1:Punto = new Punto();

// Usiamo l'operatore di selezione "." per accedere agli attributi
p1.x = 10;
p1.y = 12;

// Chiamiamo il metodo dell'oggetto
p1.output();

L'output prodotto dal metodo output dell'istanza "p1" è il seguente :

x = 10
y = 12

In questo capitolo continueremo il discorso sulle classi, introducendo nozioni che ci consentiranno un controllo maggiore e più efficace con questi strumenti.

Abbiamo visto come un metodo può gestire e manipolare gli attributi della classe a cui appartiene, agendo come una vera e propria funzione, ma interna alla classe.


Costruttori

Esiste un metodo molto importante chiamato costruttore della classe.
Il costruttore verrà richiamato automaticamente ad ogni creazione di un'istanza, ed è possibile definirne uno personalizzato.

Per dichiarare un costruttore è sufficiente dichiarare un normale metodo ma con lo stesso nome della classe :

Punto.as

package
{
	public class Punto
	{
		/* Attributi */
		var x:Number;
		var y:Number;

		/* Costruttore */
		function Punto(nuova_x:Number, nuova_y:Number)
		{
			this.x = nuova_x;
			this.y = nuova_y;
		}

		/* Metodo */
		function output():void
		{
			trace("x = " + this.x);
			trace("y = " + this.y);
		}
	}
}

Il costruttore, essendo un metodo, può prendere dei parametri alla stessa maniera di una funzione tradizionale.
Questi parametri saranno utilizzati in sostanza per inizializzare correttamente gli attributi della classe.

HelloWorld.as

package
{
	import Punto;
	import flash.display.MovieClip;

	public class HelloWorld extends MovieClip
	{
		public function HelloWorld():void
		{
			var p1:Punto = new Punto(14, 65);
			p1.output();
		}
	}
}

L'output prodotto dall'esempio soprastante (HelloWorld) è il seguente :

x = 14
y = 65

Modificatori di accesso

In ActionScript 3 è possibile assegnare dei particolari modificatori agli attributi di una classe, per assegnare ad essi un determinato livello di accessibilità e visibilità.

I modificatori di accesso si specificano subito prima il nome dell'attributo o del metodo e ne esistono quattro :

  • internal - Restringe la visibilità al pacchetto (package) di appartenenza
  • public - I membri (attributi o metodi) dichiarati come public, saranno accessibili a tutte le classi e da tutti i pacchetti visibili
  • private - Questi membri possono essere utilizzati solo all'interno della classe madre
  • protected - Restringe l'accesso solo all'interno della classe madre e alle classi derivate

Se non viene specificato alcun modificatore di accesso, ActionScript utilizzerà di default il modificatore internal.

Per fare un esempio, potremmo volere la certezza che le coordinate memorizzate nella classe Punto siano sempre dei numeri, dando la possibilità all'utente che utilizza la classe di inizializzare le istanze anche con delle stringhe, utile quando i dati vengono acquisiti da tastiera tramite ad esempio un campo di testo.

A questo scopo, potremmo rendere i due attributi x e y privati mediante il modificatore di accesso private, consentendo la modifica di questi valori solo attraverso il costruttore, che sarà progettato per effettuare sempre un casting esplicito al tipo Number.

Punto.as

package
{
	public class Punto
	{
		private var x:Number;
		private var y:Number;

		public function Punto(nuova_x:*, nuova_y:*)
		{
			this.x = new Number(nuova_x);
			this.y = new Number(nuova_y);
		}

		public function output():void
		{
			trace("x = " + this.x);
			trace("y = " + this.y);
		}
	}
}

Questo metodo ci consente di evitare assegnazioni di tipo non desiderato, ricevendo un errore 1178 nel caso in cui questo avvenga :
Tentativo di accesso alla proprietà non accessibile x mediante un riferimento con tipo statico Punto.

HelloWorld.as

package
{
	import Punto;
	import flash.display.MovieClip;

	public class HelloWorld extends MovieClip
	{
		public function HelloWorld():void
		{
			var p1:Punto = new Punto("28.7", "68.4");
			p1.output();
		}
	}
}

L'esempio soprastante produce il seguente output :

x = 28.7
y = 68.4
Condividi contenuti