3

如何创建一个 setter 方法和一个 getter 方法来管理对对象字段的访问?新的子例程如下所示:

sub new {
    my $class = shift;
    my $self = {@_};        
    bless($self,$class); # turns this into an object
}

新对象的创建如下所示:

$foo = Package::new("Package", 
    "bar", $currentBar,
    "baz", $currentBaz,
    );
4

2 回答 2

9

这不是一个好主意。

Perl 使用use strict;来处理这样的问题:

 $employee_name = "Bob";

 print "The name of the employee is $employeeName\n";

输入错误的变量名是一个常见问题。使用use strict;强制你声明你的变量,所以这样的错误可以在编译时被捕获。

但是,散列键和散列引用删除了这种保护。因此:

my $employee[0] = {}

$employee[0]->{NAME} = "Bob";

print "The name of the employee is " . $employee[0]->{name} . "\n";

当你开始谈论复杂的数据结构时,使用对象的原因之一是为了防止这些类型的错误:

 my $employee = Employee->new;
 $employee->name("Bob");
 print "The name of the employee is " . $employee->Name . "\n";

这个错误会被捕获,因为方法名是name而不是Name

允许用户随意创建自己的方法会消除我们通过使用对象获得的保护:

 my $employee = Employee->new;
 $employee->name("Bob");    #Automatic Setter/Getter
 print "The name of the employee is " . $employee->Name . "\n";  #Automatic Setter/Getter

现在,由于自动设置器和获取器,我们无法捕获错误,因为用户名的任何方法都是有效的——即使该用户犯了错误。

事实上,我设置了我的对象,所以我的对象不一定知道它的结构。foo使用方法和观察以下类bar

 sub new {
    my $class = shift;
    my $foo   = shift;
    my $bar   = shift;

    my $self = {};
    bless $self, $class;

    $self->foo($foo);
    $self->bar($bar);
    return $self;

}

sub foo {
    my $self = shift;
    my $foo  = shift;

    my $method_key = "FOO_FOO_FOO_BARRU";

    if (defined $foo) {
        $self->{$method_key} = $foo;
    }
    return $self->{$method_key};
 }

sub bar {
    my $self = shift;
    my $bar  = shift;

    my $method_key = "BAR_BAR_BAR_BANNEL";

    if (defined $bar) {
        $self->{$method_key} = $bar;
    }
    return $self->{$method_key};
}

我可以在我的构造函数foo中设置类值。bar但是,我的构造函数不知道这些值是如何存储的。它只是创建对象并将其传递给我的 getter/setter 方法。我的两种方法也不知道它们如何存储彼此的值。这就是为什么我可以为我的方法的哈希键取如此疯狂的名称,因为这仅在方法中可用,而在其他任何地方都没有。

相反,我的方法foobar都是 setter 和 getter。如果我给他们一个fooor的值bar,则该值被设置。否则,我只是返回当前值。

但是,我相信您已经知道所有这些,并且会坚持必须这样做。很好...

处理您想要做的事情的一种方法是创建一个AUTOLOAD子例程。当没有同名的其他方法子例程时,自动调用 AUTOLOAD 子例程。$AUTOLOAD包含调用的类和方法。您可以使用它来设置自己的值。

这是我的测试程序。我使用两种方法barfoo,但我可以使用任何我喜欢的方法,它仍然可以正常工作

一项更改是,我在构造函数中使用参数散列而不是值列表。除了这被认为是现代方式之外没有真正的区别,我只想与其他人的做法保持一致。

另请注意,我将方法名称标准化为全小写。这样$object->Foo$object->foo$object-FOO都是相同的方法。这样,我至少消除了大小写错误。

use strict;
use warnings;
use feature qw(say);
use Data::Dumper;

my $object = Foo->new({ -bar => "BAR_BAR",
        -foo => "FOO_FOO",
    }
);

say "Foo: " . $object->foo;
say "Bar: " . $object->bar;

$object->bar("barfu");
say "Bar: " . $object->bar;

say Dumper $object;


package Foo;

    sub new {
    my $class =      shift;
    my $param_ref  = shift;

    my $self = {};
    bless $self, $class;

    foreach my $key (keys %{$param_ref}) {

        # May or may not be a leading dash or dashes: Remove them
        (my $method = $key) =~ s/^-+//;

        $self->{$method} = $param_ref->{$key};
    }
    return $self;
}


sub AUTOLOAD {
    my $self  = shift;
    my $value = shift;

    our $AUTOLOAD;

    ( my $method = lc $AUTOLOAD ) =~ s/.*:://;

    if ($value) {
        $self->{$method} = $value;
    }
    return $self->{$method};
}
于 2012-06-04T20:48:19.343 回答
6

像这样的东西...

sub get {
    my $self = shift;
    my $field = shift;
    return $self->{$field};
}

sub set {
    my $self = shift;
    my $field = shift;
    $self->{$field} = shift;
}

...可以写

$obj->set(foo => 'my foo value');
print $obj->get('foo');

但是现在,只使用Moose是很常见的。

于 2012-06-04T18:39:57.813 回答