我们正在构建一个由模块组成的具有复杂逻辑的大型应用程序。我曾经用更简单的方法构建更大规模的方法,例如,
# fig. 1
package Foo;
sub highlevel {
my ($self, $user, $event) = @_;
my $session = $self->get_session($user);
my $result = $self->do_stuff($session, $event);
$self->save_session($session);
return $result;
};
(这当然是简化的)。返回结果,抛出异常,每个人都很高兴。
现在,我们正在转向 AnyEvent。我的模块不是最上层,所以我不能只做
# fig. 2
my $cv = AnyEvent->condvar;
# do stuff
return $cv->recv;
到目前为止,我见过的大多数 AE 模块都是这样工作的:
# fig. 3
$module->do_stuff( $input,
on_success => sub { ... },
on_error => sub { ... }
);
所以我已经重写了较低级别的方法并尝试继续使用 highlevel() 和......
# fig. 4
package Foo;
sub highlevel {
my ($self, $user, $event, %callbacks) = @_;
my $done = $callbacks{on_success};
my $error = $callbacks{on_error};
$self->get_session( $user,
on_error => $error,
on_success => sub {
my $session = shift;
$self->do_stuff( $session, $event,
on_error => $error,
on_success => sub {
my $result = shift;
$self->save_session( $session,
or_error => $error,
on_success => sub { $done->($result); }
);
}
);
}
);
};
不完全漂亮。我称之为“无限阶梯”。
现在我能想出的下一件事是一个临时状态机,其中 highlevel() 被分解为 _highlevel_stage1()、_highlevel_stage2() 等。但这也不能让我满意(它是不可维护的,并且认为很好名字而不是 stageXX 让我头疼)。
我们已经在研究一个成熟的状态机来驱动整个应用程序,但是必须为每个交互添加一个转换对我来说有点过于慷慨了。
所以问题是:编写实现业务逻辑(图 1)以在 AnyEvent 应用程序(图 3)中运行的模块的最佳实践是什么?