index | project | pods | responsabili |
NAMEperlbot - La scatola degli attrezzi degli Oggetti
DESCRIZIONELa seguente raccolta di trucchi e suggerimenti è destinata a stimolare la curiosità a proposito di cose come l'utilizzo di variabili di istanza e i meccanismi delle relazioni tra oggetto e classe. Il lettore è incoraggiato a consultare dei testi pertinenti a proposito di definizioni e metodologie per la programmazione OO (orientata agli oggetti). Questo documento non è inteso come una guida per principianti per la programmazione orientata agli oggetti né come una guida completa alle caratteristiche del Perl orientato agli oggetti, e nemmeno come guida di stile. Se state cercando delle guide per principianti, assicuratevi di leggere perlboot, perltoot e perltooc. Il motto del Perl è ancora valido: ci sono molti modi per fare le cose.
SUGGERIMENTI DI SCALABILITÀ OO
VARIABILI DI ISTANZAPer mantenere le variabili di istanza è possibile utilizzare un array anonimo o un hash anonimo. Vengono mostrati anche dei parametri con nome. package Pippo; sub new { my $tipo = shift; my %parametri = @_; my $self = {}; $self->{'Alto'} = $parametri{'Alto'}; $self->{'Basso'} = $parametri{'Basso'}; bless $self, $tipo; } package Pluto; sub new { my $tipo = shift; my %parametri = @_; my $self = []; $self->[0] = $parametri{'Sinistra'}; $self->[1] = $parametri{'Destra'}; bless $self, $tipo; } package main; $a = Pippo->new( 'Alto' => 42, 'Basso' => 11 ); print "Alto=$a->{'Alto'}\n"; print "Basso=$a->{'Basso'}\n"; $b = Pluto->new( 'Sinistra' => 78, 'Destra' => 40 ); print "Sinistra=$b->[0]\n"; print "Destra=$b->[1]\n";
VARIABILI SCALARI DI ISTANZAQuando serve solamente una variabile di istanza, può essere utilizzato uno scalare anonimo. package Pippo; sub new { my $tipo = shift; my $self; $self = shift; bless \$self, $tipo; } package main; $a = Pippo->new( 42 ); print "a=$$a\n";
EREDITARIETÀ DI VARIABILI DI ISTANZAQuesto esempio mostra come si possano ereditare variabili di istanza da una superclasse, per inclusione nella nuova classe. Ciò richiede di chiamare il costruttore della superclasse e di aggiungere le proprie variabili di istanza al nuovo oggetto. package Pluto; sub new { my $tipo = shift; my $self = {}; $self->{'tizio'} = 42; bless $self, $tipo; } package Pippo; @ISA = qw( Pluto ); sub new { my $tipo = shift; my $self = Pluto->new; $self->{'caio'} = 11; bless $self, $tipo; } package main; $a = Pippo->new; print "tizio = ", $a->{'tizio'}, "\n"; print "caio = ", $a->{'caio'}, "\n";
RELAZIONI TRA OGGETTIIl seguente codice mostra come si possano implementare relazioni di ``contenimento'' e ``utilizzo'' tra oggetti. package Pluto; sub new { my $tipo = shift; my $self = {}; $self->{'tizio'} = 42; bless $self, $tipo; } package Pippo; sub new { my $tipo = shift; my $self = {}; $self->{'Pluto'} = Pluto->new; $self->{'caio'} = 11; bless $self, $tipo; } package main; $a = Pippo->new; print "tizio = ", $a->{'Pluto'}->{'tizio'}, "\n"; print "caio = ", $a->{'caio'}, "\n";
SOVRAPPORRE I METODI DELLA SUPERCLASSEL'esempio seguente mostra come sovrapporre un metodo della superclasse e quindi chiamare il metodo sovrapposto. La pseudo-classe SUPER permette al programmatore di chiamare un metodo sovrapposto di una superclasse senza in realtà sapere dove quel metodo è definito. package Paperino; sub goo { print "ecco il goo\n" } #[sostanza appicicosa, NdT] package Pluto; @ISA = qw( Paperino ); sub google { print "c'e` google\n" } package Topolino; sub rimugina { print "sto rimuginando\n" } package Pippo; @ISA = qw( Pluto Topolino ); sub new { my $tipo = shift; bless [], $tipo; } sub grr { print "sto borbottando\n" } sub goo { my $self = shift; $self->SUPER::goo(); } sub rimugina { my $self = shift; $self->SUPER::rimugina(); } sub google { my $self = shift; $self->SUPER::google(); } package main; $pippo = Pippo->new; $pippo->rimugina; $pippo->grr; $pippo->goo; $pippo->google; Osservate che
USARE LE RELAZIONI CON SDBMQuesto esempio mostra l'interfaccia alla classe SDBM. Essa crea una relazione di ``utilizzo'' tra la classe SDBM e la nuova classe Miodbm. package Miodbm; require SDBM_File; require Tie::Hash; @ISA = qw( Tie::Hash ); sub TIEHASH { my $tipo = shift; my $ref = SDBM_File->new(@_); bless {'dbm' => $ref}, $tipo; } sub FETCH { my $self = shift; my $ref = $self->{'dbm'}; $ref->FETCH(@_); } sub STORE { my $self = shift; if (defined $_[0]){ my $ref = $self->{'dbm'}; $ref->STORE(@_); } else { die "Impossibile effettuare STORE su una chiave indefinita in Miodbm\n"; } } package main; use Fcntl qw( O_RDWR O_CREAT ); tie %pippo, "Midbm", "Sdbm", O_RDWR|O_CREAT, 0640; $pippo{'pluto'} = 123; print "pippo-pluto = $pippo{'pluto'}\n"; tie %pluto, "Midbm", "Sdbm2", O_RDWR|O_CREAT, 0640; $pluto{'Cathy'} = 456; print "pluto-Cathy = $pluto{'Cathy'}\n";
PENSARE AL RIUTILIZZO DEL CODICEUna forza dei linguaggi Orientati agli Oggetti è la facilità con la quale il vecchio codice può utilizzare il nuovo codice. Il seguente esempio mostrerà prima di tutto come si possa ostacolare il riutilizzo del codice e di seguito come si possa favorire il riutilizzo del codice. Questo primo esempio mostra una classe che utilizza una chiamata al nome del metodo per intero per accedere al metodo privato TOPOLINO(). Il secondo esempio mostrerà che è possibile effettuare una sovrapposizione del metodo TOPOLINO(). package PIPPO; sub new { my $tipo = shift; bless {}, $tipo; } sub pluto { my $self = shift; $self->PIPPO::privato::TOPOLINO; } package PIPPO::privato; sub TOPOLINO { print "in TOPOLINO\n"; } package main; $a = PIPPO->new; $a->pluto; Adesso proviamo ad effettuare una sovrapposizione del metodo TOPOLINO(). Vorremmo che PIPPO::pluto() chiamasse VAIOP::TOPOLINO(), ma ciò non può accadere perché PIPPO::pluto() chiama esplicitamente PIPPO::private::TOPOLINO(). package PIPPO; sub new { my $tipo = shift; bless {}, $tipo; } sub pluto { my $self = shift; $self->PIPPO::privato::TOPOLINO; } package PIPPO::privato; sub TOPOLINO { print "in TOPOLINO\n"; } package VAIOP; @ISA = qw( PIPPO ); sub new { my $tipo = shift; bless {}, $tipo; } sub TOPOLINO { print "in VAIOP::TOPOLINO\n"; } package main; $a = VAIOP->new; $a->pluto; Per creare codice riutilizzabile dobbiamo modificare la classe PIPPO, abbattendo la classe PIPPO::private. Il prossimo esempio mostra una classe PIPPO riutilizzabile che permette al metodo VAIOP::TOPOLINO() di essere utilizzato al posto di PIPPO::TOPOLINO(). package PIPPO; sub new { my $tipo = shift; bless {}, $tipo; } sub pluto { my $self = shift; $self->TOPOLINO; } sub TOPOLINO { print "in TOPOLINO\n"; } package VAIOP; @ISA = qw( PIPPO ); sub new { my $tipo = shift; bless {}, $tipo; } sub TOPOLINO { print "in VAIOP::TOPOLINO\n"; } package main; $a = VAIOP->new; $a->pluto;
IL CONTESTO DI CLASSE E L'OGGETTOUtilizzate l'oggetto per risolvere problemi riguardanti il contesto di package e classe. Tutto ciò di cui ha bisogno un metodo dovrebbe essere disponibile attraverso l'oggetto o dovrebbe essere passato come un parametro a quel metodo. Una classe avrà talvolta dati statici o globali per essere utilizzati dai metodi. Una sottoclasse potrebbe voler scavalcare con un override questi dati e rimpiazzarli con nuovi dati. Quando ciò accade, la superclasse può non sapere come trovare la nuova copia dei dati. Questo problema può essere risolto utilizzando l'oggetto per definire il contesto del metodo. Permettete al metodo di cercare nell'oggetto un riferimento ai dati. L'alternativa è forzare il metodo per farlo andare a caccia dei dati (``È nella mia classe o in una sottoclasse? Quale sottoclasse?''), e ciò può non essere conveniente e porterà a scrivere codice strambo. È meglio permettere semplicemente all'oggetto di dire al metodo dove sono localizzati i dati. package Pluto; %fiasco = ( 'Password' => 'XYZZY' ); sub new { my $tipo = shift; my $self = {}; $self->{'fiasco'} = \%fiasco; bless $self, $tipo; } sub enter { my $self = shift; # Non prova a indovinare se debba essere usato %Pluto::fiasco # o %Pippo::fiasco. L'oggetto sa gia` quale si debba usare, # quindi basta chiederlo. # my $fiasco = $self->{'fiasco'}; print "La parola e` ", $fiasco->{'Password'}, "\n"; } package Pippo; @ISA = qw( Pluto ); %fiasco = ( 'Password' => 'Rumple' ); sub new { my $tipo = shift; my $self = Pluto->new; $self->{'fiasco'} = \%fiasco; bless $self, $tipo; } package main; $a = Pluto->new; $b = Pippo->new; $a->enter; $b->enter;
EREDITARE UN COSTRUTTOREUn costruttore ereditabile dovrebbe utilizzare la seconda forma di package PIPPO; sub new { my $tipo = shift; my $self = {}; bless $self, $tipo; } sub topolino { print "in PIPPO::topolino()\n"; } package PLUTO; @ISA = qw(PIPPO); sub topolino { print "in PLUTO::topolino()\n"; } package main; $a = PLUTO->new; $a->topolino;
DELEGAZIONEPer alcune classi, tipo la SDBM_File, non si possono creare efficacemente sottoclassi perché queste creano oggetti esterni. Classi di questo tipo possono essere estese con una specie di tecnica di aggregazione tipo la relazione di ``utilizzo'' menzionata in precedenza o per delega. Il seguente esempio mostra la delegazione utilizzando una funzione package Miodbm; require SDBM_File; require Tie::Hash; @ISA = qw(Tie::Hash); sub TIEHASH { my $tipo = shift; my $ref = SDBM_File->new(@_); bless {'delega' => $ref}; } sub AUTOLOAD { my $self = shift; # L'interprete Perl posiziona il nome del # messaggio in una variabile chiamata $AUTOLOAD. # I messaggi DESTROY non dovrebbero essere mai propagati. return if $AUTOLOAD =~ /::DESTROY$/; # Rimuovi il nome del package. $AUTOLOAD =~ s/^Miodbm:://; # Passa il messaggio alla delega. $self->{'delega'}->$AUTOLOAD(@_); } package main; use Fcntl qw( O_RDWR O_CREAT ); tie %pippo, "Miodbm", "undbm", O_RDWR|O_CREAT, 0640; $pippo{'pluto'} = 123; print "pippo-pluto = $pippo{'pluto'}\n";
SI VEDA ANCHEperlboot, perltoot, perltooc.
TRADUZIONE
VersioneLa versione su cui si basa questa traduzione è ottenibile con: perl -MPOD2::IT -e print_pod perlbot Per maggiori informazioni sul progetto di traduzione in italiano si veda http://pod2it.sourceforge.net/ .
TraduttoreTraduzione a cura di Raffaello Galli <galliraf at googlemail punto com>.
RevisoreRevisione a cura di dree. Mon Jun 11 22:02:13 2012 |