Хотя я согласен с DVK по большей части, я должен сказать, что как только вы начинаете углубляться в массивы массивов хэшей, вы достигаете уровня сложности кода, который трудно поддерживать без большого количества вращений головок и ошибок.
На этом этапе я бы, вероятно, потянулся к объекту и классу, к небольшому синтаксическому сахару.
my $transitions = TransitionGraph->new();
$transition->add( 1, { targets => [ 2, 5 ] });
$transition->add( 2, { targets => [ 1, 5 ] });
$transition->add( 2, { targets => [ 2 ], conditions => [ $some_condition ] });
$transition->add( 2, { targets => [ 3, 4 ], conditions => [ $other_condition, $more_cond ]});
$transition->add( 3, { targets => [4,2] } );
$transition->add( 4, { targets => [3,2] } );
$transition->add( 5, { targets => [] } );
if( $transition->allowed( 1 , 3 )){
}
Реализация класса зависит от пользователя, но я бы использовал Moose.
Основным преимуществом этого является то, что вы инкапсулируете, как работает граф состояний, так что вы можете просто использовать его и беспокоиться о том, как граф работает отдельно от места его использования.
nb.в предложенном выше API add () создает новую запись, если она не существует, и обновляет эту запись, если она существует.Это оказалось проще, чем использование методов «upgrade» или «получить этот элемент, а затем изменить его».
Внутренне, это может сделать это, или что-то в этом роде:
sub add {
my ( $self , $input_state, $rules ) = @_;
my $state;
if ( $self->has_state( $input_state ) ) {
$state = $self->get_state( $input_state );
} else {
$state = TransitionGraphState->new( source_id => $input_state );
$self->add_state( $input_state, $state );
}
my $targets = delete $rules{targets};
for my $target ( @$targets ) {
$state->add_target( $target, $rules );
}
return $self;
}
sub allowed {
my ( $self, $from, $to ) = @_;
if ( not $self->has_state( $from ) ){
croak "NO source state $from in transition graph";
}
my $state = $self->get_state( $from );
return $state->allowed_to( $to );
}
Это также имеет классное преимущество: не требуется один конкретный код для работы на подузлах, вы можетесоздавайте отдельные экземпляры с их собственным поведением на тот случай, если вы хотите, чтобы одно состояние источника обрабатывалось по-разному.
$transition->add_state( 2, $some_other_class_wich_works_like_transitiongraphstate );
Надеюсь, это полезно =).