# 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,$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,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)?
解决方法
您可以使用Coro,它可以将无限梯形图转换为线性代码(通过控制反转),例如使用Coro :: rouse_cb / rouse_wait或一些Coro :: AnyEvent函数:
do_sth cb => sub { ...
成为(如果回调只调用一次):
do_sth cb => Coro::rouse_cb; my @res = Coro::rouse_wait;
您唯一的另一种选择是使用状态机,例如使用对象(有很多方法可以实现状态机,特别是在Perl中):
my $state = new MyObject; do_something callback => sub { $state->first_step_done };
在first_step完成后,您为$self-> next_state_done等注册回调.
您还可以查看一些cpan模块,例如AnyEvent :: Blackboard或AnyEvent :: Tools – 我自己没有使用它们,但也许它们可以帮助您.
至于condvars,我个人并不热衷于使用它们作为API的唯一手段 – 我更喜欢回调(因为condvars是有效的回调,这允许两者),但condvars允许你在消费者中引发异常(通过croak方法).
原文地址:https://www.jb51.cc/Perl/171907.html
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。