开发者

What's the best way to assign a method body at construction time when using Moose?

I'm using Moose (specifically MooseX::Declare) to create an iterator object, Iter which has a next method that advances state and returns 0 or 1 as required for use in a while statement. The problem I'm running into is that depending on the existence of one of the construction parameters, next needs to perform two very different sets of operations. The way I see it I have five options:

  1. if ... then in next method
  2. subclass
  3. hash dispatch
  4. symbol table manipulation
  5. put methods in different modules and load required one at construction time

Number 1 is just amateur.

Number 2 is, I suppose, the proper OOP way of doing things. I have no objections to doing it that way but seems a little bit overkill simply to override a single method.

I've often used Number 3 in the past w开发者_Go百科hen working procedurally or pseudo-functionally and it's what I'm doing now.

Number 4 is, as we all know, fraught with peril and I know nothing about Moose Guts to want to start messing around when unnecessary.

The last item, number 5 seems to me to be the most sensible (and Perlish) but like Number 2, is a little too much work. I'm really wondering if there's a fifth way I haven't considered such as hooking into the metaclass or perhaps a MooseX module that is reasonably mature.


Pass your 'next' subref into the constructor and save it in an attribute:

has next => (
    isa => 'CodeRef',
    required => 1,
    traits => ['Code'],
    handles => { next => 'execute_method' },
);

With the 'execute_method' handler provided by the native attribute 'Code' trait, you can call the 'next' method as a normal method and it will find the subref body in the attribute.

If you want to pre-define the subref body/ies and decide at construction time which version to use, you could set the value of 'next' in a builder sub according to other conditions of the object:

has next => (
    # ...
    lazy => 1,
    default => sub {
         my $self = shift;
         return sub { ... } if $self->some_condition;
         # etc etc...
    },
);


Another option is to dynamically apply a role:

package Iter;
use Moose;
use Moose::Util qw(apply_all_roles);

has next_role => (is => 'ro');

sub BUILD {
    my $self = shift;
    apply_all_roles($self, $self->next_role);
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜