我们正在构建具有复杂逻辑的大型应用程序,该逻辑由模块组成。我曾经用较简单的方法构建较大规模的方法,例如,
# 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让我头疼。
我们已经在研究一个成熟的状态机来驱动整个应用程序,但是对于每次交互都必须添加一个过渡对我来说似乎太慷慨了。
所以问题是:编写实现在AnyEvent应用程序(图3)中运行的业务逻辑(图1)的模块的最佳实践是什么?
最佳答案
您可能想使用 Future
模块将其封装在Future对象中。这就增加了语法糖来使这种清洁剂更干净。