4

用一个例子更容易解释:

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;但据我所知,这是一个全球性的事情,我希望它封装在对象中。

4

3 回答 3

5

简单、容易、非巫术的方法是在你的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-16T19:16:53.087 回答
2

$o->{sound}()AFAIK 如果不将引用存储在哈希中(可以完成),您将无法创建每个实例的方法。

方法绑定到类,对应于 perl 包。所以你应该别名化*SpecialEffects::sound = &SpecialEffects::fizz。这适用于一个类的所有对象。抱歉,这不是 javascript 等,我自己讨厌这个...

(你可以做一些半向导并动态创建一个包SpecialEffects::clonky(在运行时),它只包括sound别名clonk和 subclasses 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-16T19:23:03.770 回答
1

使用驼鹿

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 ,评论:

<omega> 但不是真的“干净”:p

<omega> 而不是那个 Moosey

<omega> 申请角色可能更好

于 2012-07-17T11:35:42.433 回答