我们正在构建具有复杂逻辑的大型应用程序,该逻辑由模块组成。我曾经用较简单的方法构建较大规模的方法,例如,

# 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对象中。这就增加了语法糖来使这种清洁剂更干净。

10-07 13:05