在实践II中与Scala actor编写应用程序 [英] Writing applications with Scala actors in practice II

查看:81
本文介绍了在实践II中与Scala actor编写应用程序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

由于我的第一个问题很长,因此我将其作为一个单独的问题进行提问。这是关于基于参与者的应用程序体系结构的另一篇文章。



通过应用程序跟踪消息路径



让我们看一段Java代码:

  public void deleteTrades(用户,日期,日期) {
PermissionSet ps = PermissionService.findPermissions(user)
if(ps.hasPermission( delete)){
Set< Trade> ts = peristence.findTrades(date);
reportService.sendCancelReports(ts);
positionService.updateWithDeletedTrades(ts);
}
}

在此代码中,我有4个单独的组件,并且交互在它们之间,过程 deleteTrades 的定义是明确的。它完全包含在方法 deleteTrades 中。



使用 Actor s并用4个独立的actor替换我的4个组件,如何跟踪(在我的脑海中)程序涉及什么?特别是如果我避免使用 !? 运算符,则很可能会发送一条消息 ConditionalDelete 到我的 PermissionActor ,它将向我的<$ c $发送一条消息 GetTradesAndDelete c> PersistenceActor 它将随后发送其他消息等。处理删除的代码将散布在我的应用程序中。





就像我之前的问题一样,人们如何处理这个问题呢?是否有一个好的建模工具可让您跟踪所有这些情况?人们是否使用 !? ?我是否将太多组件转化为 Actor s? p>

解决方案

您肯定使用5个组件。



当然,您必须要解决的问题是如何异步地链接此任务。



嗯,这实际上有点简单,但是却会使代码晦涩难懂。基本上,您向每个组件发送所需的回复。

  react {
case DeleteTrades(user,date)=> ;
PermissionService! FindPermissions(用户,DeleteTradesPermissions(日期)_)
case DeleteTradesPermissions(日期)(ps)=>
if(ps hasPermission delete)
持久性! FindTrades(日期,DeleteTradesTradeSet _)
case DeleteTradesTradeSet(ts)=>
ReportService! SendCancelReports(ts)
PositionService! UpdateWithDeletedTrades(ts)
}

这里我们使用currying在第一个传递日期返回答案。如果与互动相关的参数很多,最好将所有正在进行的交易的信息保存在本地HashSet中,并仅传递一个令牌,您将在收到答案时使用该令牌来查找该信息。



请注意,该单个参与者可以处理多个并发动作。在这种情况下,只需删除事务即可,但是您可以添加任意数量的不同操作来处理它。准备好一项操作所需的数据后,该操作便会继续。



编辑



这是如何定义这些类的一个有效示例:

  class Date 
类User
类PermissionSet

抽象类消息
案例类DeleteTradesPermission(date:Date)(ps:PermissionSet)扩展了消息
案例类FindPermissions(u:User,r:(PermissionSet) =>消息)扩展消息

FindPermissions(新用户,DeleteTradesPermission(新日期)_)

关于Curry和函数的一些解释。咖喱类 DeleteTradesPermission ,以便您可以在其上传递 Date ,并具有一些其他功能,以 PermissionSet



现在,类 FindPermissions 接收一个函数作为第二个参数。收到此消息的actor将把返回值传递给此函数,并收到 Message 作为答复发送。在此示例中,消息将具有主叫方发送的日期 PermissionSet 演员正在提供。



如果没有答案,例如 DeleteTrades SendCancelReports 和 UpdateWithDeletedTrades ,则无需传递返回消息的功能。



由于我们期望有一个函数返回那些需要答案的消息的Message作为参数,因此我们可以定义如下特征:

  trait MessageResponse1 [-T1]扩展Function1 [T1,消息] 
特征MessageResponse2 [-T1,-T2]扩展Function2 [T1,T2,Message]
...


Because my first question was so long, I'm asking this as a separate question. It's another one about the architecture of an actor-based application.

Keeping track of message paths through an Application

Let's take a piece of Java code:

public void deleteTrades(User user, Date date) {
    PermissionSet ps = permissionService.findPermissions(user)
    if (ps.hasPermission("delete")) {
        Set<Trade> ts = peristence.findTrades(date);
        reportService.sendCancelReports(ts);
        positionService.updateWithDeletedTrades(ts);
    }
}

In this code I have 4 separate components and the interaction between them required for the procedure deleteTrades is well-defined. It's completely contained in the method deleteTrades.

Modelling this with Actors and replacing my 4 components with 4 separate actors, how do I keep track (in my mind) of what a procedure involves? Particularly if I'm avoiding using the !? operator, then it's likely that I'll be sending a message ConditionalDelete to my PermissionActor, which will be sending a message GetTradesAndDelete to my PersistenceActor which will then send further messages etc etc. The code to process a delete will be strewn across my application.

It also means that pretty much every actor needs a handle on every other actor (in order to forward messages).

As in my previous question, how do people deal with this? Is there a good modelling tool which lets you keep track of all this? Do people use !? Am I turning too many components into Actors?

解决方案

You use 5 components, definitely. There are actors dealing with specific tasks, and there's an orchestrator as well.

The question you must have, of course, is how do you chain this assynchronously. Well, it's actually somewhat easy, but it can obscure the code. Basically, you send each componenent the reply you want.

react {
  case DeleteTrades(user,dates) => 
    PermissionService ! FindPermissions(user, DeleteTradesPermissions(dates) _)
  case DeleteTradesPermissions(dates)(ps) =>
    if (ps hasPermission "delete")
      Persistence ! FindTrades(date, DeleteTradesTradeSet _)
  case DeleteTradesTradeSet(ts) =>
    ReportService ! SendCancelReports(ts)
    PositionService ! UpdateWithDeletedTrades(ts)
}

Here we use currying to pass "dates" in the first returning answer. If there's a lot of parameters associated with an interaction, it might be better to keep the information for all on-going transactions in a local HashSet, and just pass a token that you'll use to locate that information when receiving the answer.

Note that this single actor can handle multiple concurrent actions. In this particular case, just Delete transactions, but you could add any number of different actions for it to handle. When the data needed for one action is ready, then that action continues.

EDIT

Here's a working example of how these classes can be defined:

class Date
class User
class PermissionSet

abstract class Message
case class DeleteTradesPermission(date: Date)(ps: PermissionSet) extends Message
case class FindPermissions(u: User, r: (PermissionSet) => Message) extends Message

FindPermissions(new User, DeleteTradesPermission(new Date) _)

A few explanations on currying and functions. The class DeleteTradesPermission is curried so that you can pass a Date on it, and have some other function complete it with a PermissionSet. This would be the pattern of the answer messages.

Now, the class FindPermissions receives as a second parameter a function. The actor receiving this message will pass the return value to this function, and will receive a Message to be sent as answer. In this example, the message will have both the Date, which the calling actor sent, and PermissionSet, which the answering actor is providing.

If no answer is expected, such as the case of DeleteTrades, SendCancelReports and UpdateWithDeletedTrades for the purposes of this example, then you don't need to pass a function of the returning message.

Since we are expecting a function which returns a Message as parameter for those messages requiring an answer, we could define traits like this:

trait MessageResponse1[-T1] extends Function1[T1, Message]
trait MessageResponse2[-T1, -T2] extends Function2[T1, T2, Message]
...

这篇关于在实践II中与Scala actor编写应用程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆