如何在运行时替换Moose对象的方法?

时间:2010-03-12 18:13:08

标签: perl methods runtime moose

是否可以在运行时替换Moose对象的方法? 通过查看Class::MOP::MethodMoose::Meta::Method继承自的)的源代码,我得出结论

 $method->{body} = sub{ my stuff }

我可以在运行时替换对象的方法。 我可以使用

获取方法
 $object->meta->find_method_by_name(<method_name>);

然而,这并没有成功。

是否可以在运行时修改方法?而且,用Moose做这件事的方法是什么?

3 个答案:

答案 0 :(得分:4)

麋与否,这听起来不是一个好主意。

相反,将对象设计为具有该方法的访问器。例如,您班级的用户可以使用My::Frobnicator->frobnicator->()来获取和调用frobnicator方法,并使用My::Frobnicator->frobnicator(sub { } )进行设置。

答案 1 :(得分:4)

思南的想法是一个很好的开始。

但是通过一些额外的调整,您可以像使用普通方法一样使用方法访问器。

#!/usr/bin/perl
use strict;
use warnings;
use Carp;

my $f = Frob->new;

$f->frob(
    sub { 
        my $self = shift;
        print "$self was frobbed\n"; 
        print Carp::longmess('frob') 
    }
);

print "\nCall frob as normal sub\n";
$f->frobit;

print "\nGoto frob\n";
$f->goto_frob;

BEGIN { 
    package Frob;
    use Moose;

    has 'frob' => (
        is => 'rw',
        isa => 'CodeRef',
    );

    sub frobit {
        &{$_[0]->frob};
    }
    sub goto_frob {
        goto $_[0]->frob;
    }

}

Frob中的两种方法非常相似。

  • frobit将所有参数传递给代码引用。
  • goto_frob将所有参数传递给代码引用,包括调用代码引用,并用代码引用替换goto_frob的堆栈帧。

使用哪种方法取决于您在堆栈中的需求。


关于修改Class::MOP::Method对象的正文存储,如$method->{body} = sub { 'foo' }

在进行OOP时违反封装永远不是一个好主意。特别是在使用Moose和Class :: MOP等复杂对象系统时。这是在惹麻烦。有时,没有其他方法可以获得你想要的东西,但即便如此,违反封装仍然是一个坏主意。

答案 2 :(得分:3)

使用提到的previously MooseX::SingletonMethod,您可以替换对象方法。

例如:

{
    package Foo;
    use MooseX::SingletonMethod;
    sub foo { say 'bar' };
}

my $bar = Foo->new;
my $baz = Foo->new;

# replace foo method just in $baz object
$baz->add_singleton_method( foo => sub { say 'baz' } );

$bar->foo;     # => bar
$baz->foo;     # => baz

另见What should I do with an object that should no longer be used in Perl?的回答,其中显示了如何使用Moose角色实现这一目标。

/ I3az /