3

I'm currently refactoring some code and am trying to remove the use of symbolic references below for dispatching a function based off input.

package Parent;
use strict;
use warnings;

sub dispatch{
  my ($self, $funcname) = @_;


  no strict "refs";
  if($self->can($funcname)){
    $self->$funcname();
  }
  else{
    $self->default_func();
  }
  use strict;
}

sub a{
  ...
}

sub b{
  ...
}

#...lots more functions...

sub default_func{
  ..
}

package Child;
use strict;
use warnings;
use Parent;

our @ISA = qw(Parent)

sub c{
  ..
}

I considered using a dispatch table like below, but this seems less than ideal since there's quite a bit of extra maintenance involved with tracking down all the subclasses and copying all the functions involved.

package Parent;
use strict;
use warnings;

{
  my $funcs ||= {
    a => sub { shift->a },
    b => sub { shift->b },
    c => sub { shift->c },
    #...lots of functions...
    DEFAULT => sub {shift->default_func}
  }
  sub dispatch{
    my ($self, $funcname) = @_;
    my $func = $funcs->{$funcname} || $funcs->{DEFAULT};
    $self->$func();
  }
}

Additionally, I considered turning the dispatch table to into a member so that the parent class doesn't have to be aware of the child classes as well. Then each child class would add its own functions to the dispatch table. Originally I did not want the dispatch table to be a member since I only wanted it to be exposed to one function but perhaps it's unavoidable. But in the end, turning it into a member does not fix the problem of the extra boilerplate and maintenance involved.

Is there a better way? This seems like a lot more work than symbolic references. I'm willing to do the extra work if it allows me to avoid a hacky solution but I'm not sure which direction to go from here.

4

2 回答 2

3

您的原始代码示例在use strict. 该$obj->$method(...)表单不需要符号引用。这是一种广泛使用的技术,被认为是一种很好的做法。

另外,请注意,即使您必须no strict,也无需use strict像示例中那样在函数末尾再次执行。strict是一个词法编译指示,所以它的效果无论如何都限制在它的包含范围内。

于 2013-10-13T16:56:45.063 回答
0

为什么不使用 AUTOLOAD?

package Parent;
use vars qw( $AUTOLOAD );
sub AUTOLOAD {
    return if $AUTOLOAD =~ m/^.*::(DESTROY)$/;
    my ($self, @params) =@_;
    return $self->$AUTOLOAD() if($self->can($AUTOLOAD)){
    return $self->default_func();
}
于 2013-10-17T12:57:49.503 回答