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";
}

より賢くしたい場合は、メソッド名と同じくらい簡単にコード参照を保存して使用できます。

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

AFAIKは、参照をハッシュに格納せずにインスタンスごとのメソッドを作成することはできません($o->{sound}()実行できます)。

メソッドは、perlパッケージに対応するクラスにバインドされます。だからあなたはalialiseする必要があります*SpecialEffects::sound = &SpecialEffects::fizz。これは、1つのクラスのすべてのオブジェクトに適用されます。申し訳ありませんが、これはjavascriptなどではありません、私はこれを自分で嫌います...

(セミウィザドライをSpecialEffects::clonky実行して、その場で(実行時に)パッケージを作成できます。これには、のsoundエイリアスclonkとサブクラスのみが含まれ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

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

<オメガ>そしてそのムージーではない

<オメガ>おそらく役割を適用する方が良い

于 2012-07-17T11:35:42.433 に答える