Действительно ли возможно заменить метод объекта Американского лося во времени выполнения? Путем рассмотрения исходного кода Class::MOP::Method
(который Moose::Meta::Method
наследовался), я завершил это путем выполнения
$method->{body} = sub{ my stuff }
Я смог бы заменить во времени выполнения метод объекта. Я могу получить использование метода
$object->meta->find_method_by_name();
Однако это не вполне удалось.
Действительно ли это мыслимо для изменения методов во время выполнения? И, что путь состоит в том, чтобы сделать это с Американским лосем?
Лось или нет, но это не очень хорошая идея.
Вместо этого спроектируйте свой объект так, чтобы у него был аксессор для метода. Например, пользователи вашего класса могут использовать My::Frobnicator->frobnicator->()
для получения и вызова метода frobnicator
и использовать My::Frobnicator->frobnicator(sub { } )
для его установки.
Идея Синан - отличное начало.
Но с небольшой дополнительной настройкой вы можете использовать свой метод доступа точно так же, как и обычный метод.
#!/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
передает все аргументы, включая вызывающую, в код ref. goto_frob
передает все аргументы, включая вызывающий объект, в ссылку кода и заменяет кадр стека goto_frob
ссылками кода. Что использовать, зависит от того, что вы хотите в стеке.
Относительно изменения хранилища тела объекта Class :: MOP :: Method
, например $ method -> {body} = sub {'foo'}
:
Никогда не рекомендуется нарушать инкапсуляцию при выполнении ООП. Особенно, когда вы работаете со сложными объектными системами, такими как Moose и Class :: MOP. Это напрашивается на неприятности. Иногда нет другого способа получить желаемое, но даже в этом случае нарушение инкапсуляции - плохая идея.
Используя ранее упомянутый 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
Также см. Этот SO-ответ на Что мне делать с объектом, который больше не должен использоваться в Perl? , где показано, как этого можно достичь с помощью ролей Moose.
/ I3az /