index | project | pods | responsabili |
NOMEperlootut - Tutorial sulla Programmazione ad Oggetti in Perl
DATAQuesto documento è stato creato nel febbraio 2011.
DESCRIZIONEQuesto documento fornisce un'introduzione alla programmazione orientata agli oggetti in Perl. Si comincia con una breve panoramica dei concetti che stanno dietro alla progettazione orientata agli oggetti. Poi vengono introdotti diversi sistemi OO presi da L <CPAN|http://search.cpan.org> che si basano su ciò che offre Perl. Di default, il sitema OO [Orientato agli Oggetti, NdT] integrato in Perl è assai minimale, lasciando fare a voi la maggior parte del lavoro. Questo minimalismo aveva parecchio senso nel 1994, ma negli anni successivi a Perl 5.0 si è visto emergere un certo numero di modelli comuni nella OO di Perl. Fortunatamente, la flessibilità di Perl ha permesso la fioritura di un ricco ecosistema di sistemi Perl per l'OO. Se si vuole sapere come funziona la OO del Perl dietro le quinte, perlobj spiega tutti i dettagli. Questo documento presuppone che siate già in grado di capire le basi del Perl, la sintassi, i tipi di variabili, gli operatori e le chiamate a subroutine. Se non si comprendono ancora questi concetti, vi preghiamo di leggere prima perlintro. Dovreste anche leggere perlsyn, perlop e perlsub.
FONDAMENTI DELL'ORIENTAMENTO AGLI OGGETTILa maggior parte dei sistemi OO condividono una serie di concetti comuni. Probabilmente avete giè sentito termini come ``classe'', ``oggetto'', metodo `` e ''attributo``. La comprensione dei concetti renderà molto più facile leggere e scrivere codice orientato agli oggetti. Se avete già familiarità con questi termini, si dovrebbe comunque sfogliare questa sezione, dal momento che spiega ogni concetto in termini dell'implementazione OO di Perl. Il sistema OO di Perl è basato sulle classi. L'OO basato sulle classi è abbastanza comune. È utilizzato da Java, C++, C#, Python, Ruby e molti altri linguaggi. Ci sono anche altri paradigmi di orientamento agli oggetti. JavaScript è il linguaggio più popolare che usa un altro paradigma. Il sistema OO di JavaScript è basato sui prototipi.
OggettoUn oggetto è una struttura dati che raggruppa insieme dati e subroutine che operano su tali dati. I dati di un oggetto si chiamano attributi e le sue subroutine sono chiamate metodi. Un oggetto può essere pensato come ad un nome (una persona, un servizio web, un computer). Un oggetto rappresenta una singola cosa discreta. Ad esempio, un oggetto potrebbe rappresentare un file. Gli attributi di un oggetto file potrebbero includere il suo percorso, il contenuto e la data dell'ultima modifica. Se abbiamo creato un oggetto per rappresentare /etc/hostname su una macchina chiamata ``pippo.esempio.com'', il percorso di questo oggetto sarebbe ``/etc/hostname'', il suo contenuto sarebbe ``pippo\n'' e la data dell'ultima modifica sarebbero 1304974868 secondi dall'inizio dell'epoch. I metodi associati ad un file potrebbero includere In Perl, la maggior parte degli oggetti sono hash, ma i sistemi OO che consigliamo vi preservano dal dover preoccuparsi di questo aspetto. In pratica, è meglio considerare la struttura dati interna di un oggetto non trasparente.
ClasseUna classe definisce il comportamento di una categoria di oggetti. Una classe è un nome di una categoria (come ``File'') e una classe definisce anche il comportamento degli oggetti di quella categoria. Tutti gli oggetti appartengono ad una classe specifica. Ad esempio, il nostro oggetto
/etc/hostname appartiene alla classe In Perl, un package può essere una classe. La differenza tra un package
che è una classe e uno che non lo è si basa su come viene utilizzato il package.
Ecco la nostra ``dichiarazione di classe'' per la classe package File; In Perl, non vi è alcuna parola chiave speciale per costruire un oggetto.
Tuttavia, la maggior parte dei moduli OO su CPAN utilizzano un metodo denominato my $nome_host = File-> new ( percorso => '/etc/hostname', contenuto => "pippo\n", data_ultima_modifica => 1304974868, ); (Non vi preoccupate riguardo all'operatore
BlessingCome abbiamo detto in precedenza, la maggior parte degli oggetti in Perl sono hash, ma un oggetto
può essere un'istanza di qualsiasi tipo di dato (scalare, array, ecc.). Trasformare una
semplice struttura dati in un oggetto viene fatto eseguendo un blessing di quella struttura
dati utilizzando la funzione Perl Sebbene vi raccomandiamo vivamente di non costruire i vostri oggetti da zero, si dovrebbe conoscere il termine bless. Una struttura dati blessed (conosciuta anche come ``referente'') è un oggetto. A volte diciamo che un oggetto è stato ``blessed into a class'', ovvero sottoposto a bless di quella classe. Una volta che un referente è stato sottoposto a bless, la funzione use Scalar::Util 'blessed'; print blessed($hash); # undef print blessed($nome_host); # File
CostruttoreUn costruttore crea un nuovo oggetto. In Perl, il costruttore di una classe
è solo un altro metodo, a differenza di altri linguaggi che forniscono
la sintassi per i costruttori. La maggior parte della classi in Perl utilizza my $file = File->new(...);
MetodiAvete già imparato che un metodo è una subroutine che opera su un oggetto. Si può pensare ad un metodo come le cose che un oggetto può fare. Se un oggetto è un nome, allora i metodi sono i suoi verbi (salvare, stampare, aprire). In Perl, i metodi sono semplicemente subroutine che risiedono nel pacchetto di una classe. I metodi sono sempre scritti per ricevere l'oggetto come proprio primo argomento: sub stampa_info { my $self = shift; print "Questo file sta in ", $self->percorso, "\n"; } $file->stampa_info; # Il file sta in /etc/hostname Cosa rende un metodo speciale è il modo in cui viene chiamato. L'operatore freccia
( Quando facciamo una chiamata al metodo, Perl stabilisce che il metodo invocant sia passato come primo argomento. Invocant è un nome di fantasia che indica la cosa sul lato sinistro della freccia. Invocant può essere una classe, un nome o un oggetto. Possiamo anche passare al metodo degli argomenti aggiuntivi: sub stampa_info { my $self = shift; my $prefisso = shift // "Questo file sta in "; print $prefisso, ", ", $self->percorso, "\n"; } $file->stampa_info("Il file e` posizionato in "); # Il file e` posizionato in /etc/hostname
AttributiOgni classe può definire i suoi attributi. Quando istanziamo un oggetto,
assegniamo i valori di tali attributi. Ad esempio, ogni oggetto Perl non ha alcuna sintassi speciale per gli attributi. Dietro le quinte, gli attributi sono spesso memorizzati come chiavi del (sottostante) hash che è l'oggetto, ma non ci si deve preoccupare di questo aspetto. Si consiglia di accedere agli attributi solo tramite metodi accessor.
Questi sono metodi che possono ottenere o impostare il valore di ogni attributo.
L'abbiamo visto in precedenza nell'esempio Si potrebbe anche incontrare i termini getter e setter. Questi sono due tipi di accessor. Un getter ottiene il valore dell'attributo, mentre un setter lo imposta. Un altro termine per un setter è mutator. Gli attributi sono solitamente definiti come di sola lettura o di lettura e scrittura. Gli attributi di sola scrittura possono essere impostati solo quando l'oggetto viene creato, mentre gli attributi di lettura-scrittura possono essere modificati in qualsiasi momento. Il valore di un attributo può essere esso stesso un altro oggetto. Per esempio,
invece di restituire il suo istante di ultima modifica come un numero, la classe È possibile avere una classe che non espone pubblicamente attributi impostabili. Non tutte le classi hanno attributi e metodi.
PolimorfismoIl polimorfismo è un modo elegante per dire che gli oggetti provenienti da due
diverse classi condividono delle API. Per esempio, potremmo avere le classi Mentre le due classi possono differire in molti modi, per quanto riguarda il
metodo Il polimorfismo è uno dei concetti chiave della progettazione orientata agli oggetti.
EreditarietàL'ereditarietà consente di creare una versione specializzata di una classe esistente. L'ereditarietà consente alla nuova classe di riutilizzare i metodi e gli attributi di un'altra classe. Ad esempio, potremmo creare una classe Si fa spesso riferimento a relazioni di ereditarietà come relazioni genitore-figlio o
package File::MP3; use parent 'File'; Il modulo parent [genitore, NdT] è uno dei diversi modi con i quali Perl vi consente di definire rapporti di ereditarietà. Perl permette l'ereditarietà multipla, il che significa che una classe può ereditare da genitori multipli. Sebbene questo sia possibile, si sconsiglia vivamente di farlo. Generalmente, è possibile utilizzare ruoli per fare tutto ciò che si può fare con l'ereditarietà multipla, ma in un modo più pulito. Si noti che non c'è niente di sbagliato con la definizione di sottoclassi multiple di una
determinata classe. Questa è una prassi usuale e sicura. Ad esempio, potremmo definire le
classi
Override [ridefinizione, NdT] dei metodi e risoluzione dei metodiL'ereditarietà consente a due classi di condividere il codice. Di default, ogni metodo
nella classe genitore è disponibile anche nella classe figlio. Il figlio può
esplicitamente fare un override del metodo di un genitore per fornire la propria
implementazione. Per esempio, se abbiamo un oggetto my $gabbia = File::MP3->new( percorso => 'mp3s/My-Body-Is-a-Cage.mp3', contenuto => $dati_mp3, data_ultima_modifica => 1304974868, titolo => 'My Body Is a Cage', # Il Mio Corpo E` una Gabbia ); $gabbia->stampa_info; # Il file sta in mp3s/My-Body-Is-a-Cage.mp3 Se volessimo includere il titolo dell'mp3 nella presentazione????, potremmo effettuare l'override del metodo: package File::MP3; use parent 'File'; sub stampa_info { my $self = shift; print "Questo file sta in ", $self->percorso, "\n"; print "Il suo titolo e` ", $self->titolo, "\n"; } $gabbia->stampa_info; # Il file sta in mp3s/My-Body-Is-a-Cage.mp3 # Il suo titolo e` My Body Is a Cage Il processo di determinazione su quale metodo dovrebbe essere usato, viene chiamato
metodo di risoluzione. Cosa fa Perl è guardare prima la classe dell'oggetto
(in questo caso Se È possibile chiamare in modo esplicito un metodo genitore da un figlio: package File::MP3; use parent 'File'; sub stampa_info { my $self = shift; $self->SUPER::stampa_info(); print "Il suo titolo e` ", $self->titolo, "\n"; } La parte Abbiamo accennato in precedenza all'ereditarietà multipla. Il problema principale con l'ereditarietà multipla è che complica notevolmente il metodo di risoluzione. Per maggiori dettagli si veda perlobj.
IncapsulamentoL'incapsulamento è l'idea che un oggetto sia non trasparente. Quando un altro sviluppatore utilizza la vostra classe, non ha bisogno di sapere come è stata implementata, ha solo bisogno di sapere che cosa fa. L'incapsulamento è importante per diverse ragioni. In primo luogo, permette di separare le API pubbliche dall'implementazione privata. Ciò significa che potete cambiare questa implementazione senza violare le API. In secondo luogo, quando le classi sono ben incapsulate, per loro diventa più facile divenire una sottoclasse. Idealmente, una sottoclasse utilizza le stesse API di accesso ai dati degli oggetti che utilizzano la sua classe genitore. In realtà, fare una sottoclasse a volte implica la violazione dell'incapsulamento, ma delle buone API possono minimizzare la necessità di farlo. Abbiamo accennato in precedenza che, dietro le quinte, in Perl molti oggetti sono implementati come hash. Il principio di incapsulamento ci dice che non dovremmo farvi affidamento. Invece, per accedere ai dati contenuti in questo hash dovremmo usare gli accessor dei metodi. Tutti i sistemi ad oggetti che vi consigliamo qui di seguito, automatizzano la generazione degli accessor dei metodi. Se ne usate uno, non dovreste mai accedere direttamente all'oggetto come hash.
ComposizioneNel codice orientato agli oggetti, spesso ci si accorge che un oggetto fa riferimento ad un altro oggetto. Questo si chiama composizione oppure relazione has-a [ha-un, NdT]. In precedenza abbiamo detto che l'accessor
RuoliUn ruolo è qualcosa che una classe fa, piuttosto che qualcosa che <è>. I ruoli sono relativamente nuovi per Perl, ma sono diventati molto popolari. I ruoli sono applicati alle classi. A volte si dice che le classi consumano i ruoli. I ruoli sono un'alternativa all'ereditarietè per fornire il polimorfismo.
Supponiamo di avere due classi, Avremmo potuto ereditare entrambe le classi da un progenitore comune, come
Questo è il caso nel quale i ruoli fanno la loro comparsa. Ha molto senso creare un ruolo
Perl non ha alcuna modalità integrata per esprimere i ruoli. In passato, le persone stringevano semplicemente i denti ed utilizzavano l'ereditarietà multipla. Oggigiorno, ci sono diverse buone scelte su CPAN per l'utilizzo dei ruoli.
Quando Utilizzare l'OOL'Orientamento agli Oggetti non è la migliore soluzione per ogni problema. In Perl Best Practices (copyright 2004, pubblicato da O'Reilly Media, Inc.), Damian Conway fornisce un elenco di criteri da utilizzare per decidere se l'OO è la giusta scelta per il vostro problema:
SISTEMI OO IN PERLCome abbiamo accennato in precedenza, il sitema OO integrato in Perl è minimale, ma anche abbastanza flessibile. Nel corso degli anni, molte persone hanno sviluppato sistemi che si basano sul sitema OO integrato in Perl per fornire maggiori funzionalità e vantaggi. Si consiglia vivamente di utilizzare uno di questi sistemi. Anche il più minimale di questi elimina molto di quel codice ripetitivo che fa sempre le stesse cose. In Perl non c'è davvero nessun buon motivo per scrivere le classi da zero. Se siete interessati alle interiora che sono alla base di questi sistemi, date un'occhiata a perlobj.
MooseMoose si pubblicizza come un ``sistema postmoderno di oggetti per Perl 5''. Non abbiate paura, l'etichetta ``postmoderno'' è un richiamo alla descrizione di Larry sul Perl quale ``primo linguaggio postmoderno per computer''.
Ecco la nostra classe package File; use Moose; has percorso => ( is => 'ro' ); # ['ro' sta per Read Only, di sola lettura, NdT] has contenuto => ( is => 'ro' ); has data_ultima_modifica => ( is => 'ro' ); sub stampa_info { my $self = shift; print "Questo file sta in ", $self->percorso, "\n"; }
Naturalmente,
L'impatto di questo tempo di caricamento può essere un problema quando la velocità di avvio è importante, ad esempio con uno script a riga di comando o uno script CGI standard che deve essere caricato ogni volta che viene eseguito. Prima di farsi prendere dal panico, sappiate che molte persone usano
MouseSe si prova
Infine, viene fornito con un modulo Gli autori di
Class::Accessorthe Class::Accessor manpage è l'antitesi di Tuttavia è molto semplice, è scritto in puro e semplice Perl, e non ha dipendenze che non siano moduli già presenti nell'installazione base di Perl. Esso fornisce anche delle API ``a-la Moose'', su richiesta per le funzionalità supportate????. Anche se non fa molte cose, è ancora preferibile allo scrivere la vostra classe da zero. Ecco la nostra classe package File; use Class::Accessor 'antlers'; has percorso => ( is => 'ro' ); has contenuto => ( is => 'ro' ); has data_ultima_modifica => ( is => 'ro' ); sub stampa_info { my $self = shift; print "Questo file sta in ", $self->percorso, "\n"; } Il parametro di importazione Come
Object::TinyInfine, abbiamo the Object::Tiny manpage. Questo modulo è davvero degno del suo nome. Ha delle API incredibilmente minimali e assolutamente senza dipendenze (core o meno). Tuttavia, pensiamo che sia molto più facile da usare rispetto alla scrittura da zero del proprio codice OO. Ecco ancora una volta la nostra classe package File; use Object::Tiny qw( percorso contenuto data_ultima_modifica ); sub stampa_info { my $self = shift; print "Questo file sta in ", $self->percorso, "\n"; } Questo è tutto! Con
Role::TinyCome abbiamo accennato prima, i ruoli forniscono un'alternativa all'ereditarietà, ma Perl non ha alcun supporto integrato per i ruoli. Se si sceglie di utilizzare Moose, esso è dotato di una implementazione dei ruoli sviluppata in modo completo. Tuttavia, se si utilizza uno degli altri moduli OO che abbiamo raccomandato, è comunque possibile utilizzare i ruoli con the Role::Tiny manpage.
Sommario dei Sistemi OOEcco un breve riassunto delle alternative che abbiamo affrontato:
Usate
Altri Sistemi OOCi sono letteralmente dozzine di altri moduli su CPAN relativi alla OO, oltre a quelli di cui ci si è occupati qui, ed è probabile imbattersene in diversi altri se si lavora con il codice di altre persone. Inoltre, in un sacco di codice attualmente in produzione tutto l'OO è scritto ``a mano'', utilizzando solo le funzionalità OO integrate in Perl. Se avete bisogno di manutenere tale codice, dovreste leggere perlobj per capire esattamente come funziona l'OO integrato in Perl.
CONCLUSIONECome detto precedentemente, il sistema minimale per l'OO di Perl ha portato ad una profusione di sistemi OO su CPAN. Sebbene si possa ancora arrivare all'osso e scrivere le proprie classi a mano, non c'è alcuna ragione per non scriverle con modern Perl. Per piccoli sistemi, sia the Object::Tiny manpage che the Class::Accessor manpage forniscono entrambi dei sistemi minimali ad oggetti che si prendono cura per voi delle solite cose basilari. Per i progetti più grandi, Moose fornisce un ricco insieme di funzionalità che consentono di concentrarsi sull'implementazione della logica applicativa. Vi invitiamo a valutare e giocare con Moose, the Class::Accessor manpage e the Object::Tiny manpage per capire quale sia per voi il sistema OO più appropriato.
TRADUZIONE
VersioneLa versione su cui si basa questa traduzione è ottenibile con: perl -MPOD2::IT -e print_pod perlootut Per maggiori informazioni sul progetto di traduzione in italiano si veda http://pod2it.sourceforge.net/ .
TraduttoreTraduzione a cura di dree.
RevisoreRevisione a cura di . Mon Jun 11 22:02:20 2012 |