Ваши классы использования, как написано, эквивалентны
BEGIN {
require step_1_class;
step_1_class->import() if step_1_class->can('import');
require step_2_class;
step_2_class->import() if step_2_class->can('import');
...
}
Это можно переписать как
BEGIN {
foreach my $i ( 1 .. $max_class ) {
eval "require step_${i}_class";
"step_${i}_class"->import() if "step_${i}_class"->can('import');
}
}
Новые операторы немного сложнее, так как у вас есть отдельные переменные и разные параметры, однако это можно обойти, сохранив все объекты в массиве, а также предварительно обработав параметры, например
my @steps;
my @parameters = ( undef, \@args1, \@args2, \@args3, [ @args4, $args_4_1], ...);
for ($i = 1; $i <= $max_class; $i++) {
push @steps, "step_${i}_class"->new(@{$parameters[$i]});
}