将Moose风格属性访问器添加到你的Perl类中
坦白说,为现成的Perl类编写属性访问器是重复且不太有趣的。当然,你可以使用 Moose 或 Class::Accessor 来减轻负担,但有时你希望手动实现解决方案,无需依赖项。
一个典型的类
下面的Point类有两个属性(x,y),并且为每个属性都编写了get/set方法,采用纯Perl面向对象风格。
package Point;
sub new {
my ($class, $x, $y) = @_;
my $self = {
x => $x,
y => $y,
};
return bless $self, $class;
}
sub get_x {
return $_[0]->{x};
}
sub set_x {
return $_[0]->{x} = $_[1];
}
sub get_y {
return $_[0]->{y};
}
sub set_y {
return $_[0]->{y} = $_[1];
}
1;
另一种方法
上周Rob Hoelz写了一篇关于Perl类型全局变量的有趣的文章,我们可以使用类型全局变量来帮助我们的Point类属性访问器。这是更新后的类
package Point;
my @attributes;
BEGIN {
@attributes = qw/x y/;
no strict 'refs';
for my $accessor ( @attributes ) {
*{$accessor} = sub {
@_ > 1 ? $_[0]->{$accessor} = $_[1] : $_[0]->{$accessor} };
}
}
sub new {
my ($class, $args) = @_;
my $self = bless {}, $class;
for my $key ( @attributes ) {
$self->{$key} = $args->{$key} if exists $args->{$key}
}
return $self;
}
1;
删除了单独的get/set访问器,取而代之的是BEGIN块。该块关闭了严格引用(仅对块有效)并为每个属性创建一个匿名get/set子例程的类型全局引用。构造函数已被更新为接受一个参数哈希引用($args)并设置任何在$args中找到的属性值。
这种方法的优点是,添加额外属性只需简单地将属性名添加到@attributes中,而原始Point类需要添加两个新方法并更新构造函数方法才能添加新属性。此外,这种方法还支持Moose风格语法:当提供参数时设置属性值,否则获取它。例如
$point->x; #get x
$point->x(5); #set x to 5
虽然这种方法确实提供了比纯Perl面向对象更快的可扩展性和更简洁的语法,但它也是有限的。例如,在不添加一些丑陋的if-else代码的情况下很难添加属性特定的行为。因此,它可能最适合涉及简单类和许多属性的场景。
来源
感谢David Golden,他令人惊叹的HTTP::Tiny源代码启发了这篇文章。
这篇文章最初发表在PerlTricks.com。
标签
反馈
这篇文章有什么问题吗?请通过在GitHub上打开问题或拉取请求来帮助我们。