Perl objects - class variable initialization

2019-07-24 21:45发布

问题:

I've just begun designing a Perl class, and my only prior experience with OOP is with C++, a long time ago.

There are a few items of data that I need to be "class variables" - shared by all instances. I'd like for them to be initialized prior to the first time I instantiate an object, and I'd like for the main program that issues use MyClass to be able to provide a parameter for that initialization process.

Here's a working example of a class with a class variable:

package MyClass;
use strict;
use warnings;

# class variable ('our' for package visibility)                                                                 
#                                                                                                               
our $class_variable = 3;  # Would like to bind to a variable                                                    

sub new {
     my $class = shift;
     my $self = { };
     bless $self, $class;
     return $self;
}

sub method {
    my $self = shift;
    print "class_variable: $class_variable\n";
    ++$class_variable; # prove that other instances will see this change                                        
}

And here's a demo:

#!/usr/bin/perl                                                                                                 

use strict;
use warnings;
use MyClass;

my $foo = MyClass->new();
$foo->method(); # show the class variable, and increment it.

my $bar = MyClass->new();
$bar->method(); # this will show the incremented class variable.

Is there any way for the main program to specify a value for $class_variable? The value would be known at compile time in the main program.

回答1:

Using the import facility:

package MyClass;

my $class_variable;

sub import
{
  (undef, my $new_class_variable) = @_;

  if (defined $class_variable and
      defined $new_class_variable and
      $class_variable ne $new_class_variable)
  {
    warn '$MyClass::class_variable redefined';
  }

  $class_variable = $new_class_variable if defined $new_class_variable;
}

Pass the value when you use the module:

use MyClass qw(42);

It's not exactly idiomatic Perl, but it's not uncommon either. That sanity check in the middle of the function should give you a hint about why it might not be the best approach in all cases. If MyClass is only supposed to be used from a top-level script, you could enforce that sanity check instead:

caller eq 'main' or die 'MyClass can only be used from package main';


回答2:

You can also make the variable "private" by declaring it with my instead of our. In such a case, you have to provide a class method to initialize it:

my $class_variable = 3;

sub initialize_variable {
    my ($class, $value) = @_;
    die "Ivalid value $value.\n" unless $value =~ /^[0-9]+$/;
    $class_variable = $value;
}

And then in the programme:

'MyClass'->initialize_variable(42);


回答3:

$MyClass::class_variable = "some value";


回答4:

You can also use a Class method:

Ex:

package myclass;

our $class_variable = 5;

sub myclass_method{

    my ($class, $new_class_variable_value) = @_;

    if( $class_variable != $new_class_variable_value )
    {
        ## set the new value of the class/package variable
        $class_variable = $new_class_variable_value;
    }
}

In your script you'd invoke this by doing:

myclass::myclass_method('myclass', 7);