更容易用一个例子来解释:
my $o = SpecialEffects->new( "config" => 'a' );
my $p = SpecialEffects->new( "config" => 'b' );
$o->sound(); # aliased to fizz(); same as $o->fizz()
$p->sound(); # aliased to clonk(); same as $p->clonk()在Perl中可以做到这一点吗?也许使用了一些typeglob或coderef技巧?
我尽量保持SpecialEffects接口的简洁性。我不希望开始构建对象层次结构。sound()方法是公开的,只有它的行为可以稍微配置。
我已经知道可以使用*sound = \&fizz;作为别名,但据我所知,这是一个全局问题,我希望将其封装在对象中。
发布于 2012-07-17 03:16:53
简单、容易、非奇妙的方式是在SpecialEffects对象中存储一个方法名,根据需要设置它,然后从sound()调用它。
package SpecialEffects;
sub new {
my $type = shift;
my %options = @_;
my $self = {};
bless $self, $type;
if($options{config} eq 'a') {
$self->{sound_method} = 'fizz';
} elsif($options{config} eq 'b') {
$self->{sound_method} = 'clonk';
}
return $self;
}
sub sound {
my $self = shift;
my $method_name = $self->{sound_method};
$self->$method_name();
}
sub fizz {
print "fizz\n";
}
sub clonk {
print "clonk\n";
}如果您想更精妙地存储和使用coderef,您可以像存储和使用方法名一样简单。
package SpecialEffects;
sub new {
my $type = shift;
my %options = @_;
my $self = {};
bless $self, $type;
if($options{config} eq 'a') {
$self->{sound_code} = $self->can('fizz');
} elsif($options{config} eq 'b') {
$self->{sound_code} = $self->can('clonk');
}
return $self;
}
sub sound {
my $self = shift;
my $code = $self->{sound_code};
$self->$code();
}发布于 2012-07-17 03:23:04
如果不将引用存储在散列中,就不能创建每个实例的方法(可以使用$o->{sound}())。
方法绑定到类,这些类对应于perl包。所以你应该疏远*SpecialEffects::sound = &SpecialEffects::fizz。这适用于一个类的所有对象。对不起,这不是javascript等,我讨厌这一点…
(您可以执行一些半精灵操作并动态创建一个包SpecialEffects::clonky (在运行时),它只包含clonk的sound别名和子类SpecialEffects。然后再祝福你的推荐人。这实际上是您不想要的层次结构,但您不必实际生成.pm文件
编辑:我不确定这到底是怎么做的,但它遵循以下的路线↓如果它能工作,这是一个半优雅的解决方案(它会弄乱你的名字空间)
sub whatSoundShallIMake {
my ($self, $sound) = @_;
no strict 'refs';
my $newPackageName = "SpecialEffects::make$sound";
*{"$newPackageName\::sound"} = &{"SpecialEffects::$sound"}; # make the alias
@{"$newPackageName\::ISA"} = qw(SpecialEffects); # subclass
return bless $self, $newPackageName; # rebless
}
say ref $o;
# prints "SpecialEffects"
$o = whatSoundShallIMake($o, "fizz");
say ref $0;
# prints "SpecialEffects::makefizz")
发布于 2012-07-17 19:35:42
使用Moose
package SpecialEffects;
use Moose;
has '_method' => (is => 'ro', isa => 'CodeRef');
around BUILDARGS => sub {
my ($orig, $class, %args) = @_;
my %map = (a => 'fizz', b => 'clonk');
if (my $config = delete $args{config}) {
$args{_method} = $class->can($map{$config});
}
return $class->$orig(%args);
};
sub sound {shift->_method->(@_)}
sub fizz {return 'fizz';}
sub clonk {return 'clonk';}
1;use Test::More;
use SpecialEffects;
my $o = SpecialEffects->new(config => 'a');
is($o->sound, 'fizz');
my $p = SpecialEffects->new(config => 'b');
is($p->sound, 'clonk');
done_testing;代码信用转到#moose中的omega,评论:
,但不是真正的“干净”:p
而不是那个穆西
应用角色可能会更好
https://stackoverflow.com/questions/11510973
复制相似问题