2010-03-12 2 views
6

런타임에 Moose 객체의 메소드를 대체 할 수 있습니까? 는 (에서 어떤 Moose::Meta::Method 상속) Class::MOP::Method의 소스 코드를 살펴보면 나는런타임에 Moose 객체의 메소드를 어떻게 대체합니까?

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

을 수행하여 내가 런타임에 객체의 방법을 대체 할 수있을 것이라고 결론을 내렸다. 나는

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

그러나,이 꽤 잘 안 사용 방법을 얻을 수 있습니다.

런타임에 메서드를 수정하는 것이 좋습니다. 그리고, 무스로 그것을하는 방법은 무엇입니까?

답변

4

무스인지 아닌지는 좋은 생각 같지 않습니다.

대신 해당 메서드에 대한 접근자를 갖도록 개체를 디자인하십시오. 예를 들어, 클래스 사용자는 My::Frobnicator->frobnicator->()을 사용하여 frobnicator 메소드를 가져와 호출하고 My::Frobnicator->frobnicator(sub { })을 사용하여 설정할 수 있습니다.

+1

시안 아주 좋은 생각 :) 감사합니다. – xxxxxxx

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 코드 심판에 invocant 포함한 모든 인수를 전달합니다.
  • goto_frob은 invocant를 포함한 모든 인수를 코드 ref에 전달하고 goto_frob의 스택 프레임을 코드 refs로 바꿉니다.

어느 것이 스택에 원하는지에 따라 다릅니다.

그것은 당신이 OOP를 수행 할 때 캡슐화를 위반하는 것이 좋습니다 결코 그래서 $method->{body} = sub { 'foo' }처럼 Class::MOP::Method 개체의 몸 스토리지를 munging에 관한


. 특히 Moose 및 Class :: MOP와 같은 복잡한 객체 시스템으로 작업 할 때는 그렇지 않습니다. 그것은 문제를 요구하고 있습니다. 때로는 원하는 것을 얻을 수있는 다른 방법이 없지만 캡슐화를 위반하는 것은 여전히 ​​나쁜 생각입니다.

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 

또한이 SO 이는 무스 역할을 사용하여 달성 될 수있는 방법을 도시하는 What should I do with an object that should no longer be used in Perl? 대답 참조.

/l3az/