6

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

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

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

 $object->meta->find_method_by_name(<method_name>);

然而,这并不完全奏效。

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

4

3 回答 3

4

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

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

于 2010-03-12T18:37:44.317 回答
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 等复杂对象系统时。这是自找麻烦。有时,没有其他方法可以得到你想要的东西,但即便如此,违反封装仍然是一个坏主意。

于 2010-03-12T19:50:32.610 回答
3

使用前面提到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

另请参阅关于我应该如何处理不应再在 Perl 中使用的对象的这个 SO 答案?,它显示了如何使用 Moose 角色来实现这一点。

/I3az/

于 2010-03-12T20:24:51.587 回答