2009-06-29 7 views
12

Necesito un atributo de clase en Moose. Ahora estoy diciendo:¿Cuál es la mejor manera de crear un atributo de clase en Moose?

#!/usr/bin/perl 

use 5.010; 
use strict; 
use warnings; 
use MooseX::Declare; 

class User { 
    has id  => (isa => "Str", is => 'ro', builder => '_get_id'); 
    has name => (isa => "Str", is => 'ro'); 
    has balance => (isa => "Num", is => 'rw', default => 0); 

    #FIXME: this should use a database 
    method _get_id { 
     state $id = 0; #I would like this to be a class attribute 
     return $id++; 
    } 
} 

my @users; 
for my $name (qw/alice bob charlie/) { 
    push @users, User->new(name => $name); 
}; 

for my $user (@users) { 
    print $user->name, " has an id of ", $user->id, "\n"; 
} 

Respuesta

8

Encontré MooseX :: ClassAttribute, pero se ve feo. ¿Es esta la manera más limpia?

#!/usr/bin/perl 

use 5.010; 
use strict; 
use warnings; 
use MooseX::Declare; 

class User { 
    use MooseX::ClassAttribute; 

    class_has id_pool => (isa => "Int", is => 'rw', default => 0); 

    has id  => (isa => "Str", is => 'ro', builder => '_get_id'); 
    has name => (isa => "Str", is => 'ro'); 
    has balance => (isa => "Num", is => 'rw', default => 0); 

    #FIXME: this should use a database 
    method _get_id { 
     return __PACKAGE__->id_pool(__PACKAGE__->id_pool+1); 
    } 
} 

my @users; 
for my $name (qw/alice bob charlie/) { 
    push @users, User->new(name => $name); 
}; 

for my $user (@users) { 
    print $user->name, " has an id of ", $user->id, "\n"; 
} 
+0

Esa es la forma correcta. También puedes crear una clase (por así decirlo) si la prefieres en un paquete separado, mira lo que hace ClassAttribute bajo el capó – castaway

+0

No es 'use strict' y' use warnings' redundante con 'use MooseX :: Declare' ? –

+0

@Robert P Probablemente, recién comenzaba a utilizar MooseX :: Declare cuando escribí esto. –

2

Honestamente, no creo que sea necesario tener todos esos problemas para los atributos de clase. Para los atributos de clase de solo lectura, solo uso un sub que devuelve una constante. Para los atributos de lectura-escritura, una variable de estado simple en el paquete por lo general hace el truco (que aún no se han topado con ningún escenario en el que necesitaba algo más complicado.)

state $count = 0; 
method _get_id { 
    return ++$count; 
} 

Un bloque privado con un léxico puede ser utilizado si necesita compatibilidad previa a 5.10.

+2

ah, pero id_pool no es necesariamente de solo lectura, quiero un atributo de clase verdadero que tenga un descriptor de acceso. No quiero tener que volver a escribir el código cuando decida mover el grupo de ID a una base de datos. Si se tratara de un programa de acceso, solo necesitaría modificar cómo funcionaba el acceso, con una variable de estado que necesitaría cambiar todas las referencias o convertirlo en un escalar vinculado. –

Cuestiones relacionadas