通过前面的文章我们总结了几个常见的actor设计模式,但此处不得不提前介绍一下在Akka中消息的设计模式。随着对Akka的使用,我们会发现,使用Akka设计系统其实就是面向消息编程。actor之间消息设计的是否合理,往往意味着Akka应用设计的是否合理。那么actor之间的消息该如何设计呢?

  命令和事件

  actor之间都是通过“消息”进行通信的,对各种各样的“消息”进行分析,我们可以把它简单的分为命令和事件两类。命令,是指一个actor给另外一个actor发送指令做相关的业务逻辑;事件,则是actor对某个命令的响应结果,或者对其他事件的响应结果。简单来说,命令是主动让actor做出某种响应,例如发送Stop命令让其他actor销毁自己;事件,往往意味着某种通知,例如actor销毁之前发送Stopped事件给它的supervisor。

  我们在用Akka开发应用时候,一定要仔细认真的把系统间的消息按照定义划分为命令和事件。具体如何划分可以参考这两种消息的具体定义或DDD(领域驱动设计)相关概念。此处我们只介绍在代码结构上如何设计它们。

trait Message{
// 消息创建的时间
final val at:Long = System.currentTimeMillis()
}
trait Command extends Message
trait Event extends Message trait MasterCommand extends Command{
// 定义MasterCommand公有的方法或字段
} object MasterCommand{
case class StartWork(message:String) extends MasterCommand
}
trait MasterEvent extends Event{
// 定义MasterEvent公有的方法或字段
} object MasterEvent{
case class WorkStarted(message:String) extends MasterCommand
}

  上面是我在开发时常用的设计消息的框架。其中Message这个trait表示对消息的抽象,其中只有一个at字段,是消息创建的时间。Command继承Message,表示对命令的抽象。Event也继承Message,表示对事件的抽象。MasterCommand这个trait继承Command标志master发出的命令。所有master发出的具体命令放在与MasterCommand这个trait同名的object中。当然也可以不同名,只要在一个object中即可。把master具体命令放到一个object中,只是为了对其进行名称的限定。如果其他类型的actor也有一个StartWork命令,在同一个actor中要对这两个StartWork同时做响应的话,会引起歧义。所以我一般都用object来进行隔离,当然是用package或者把StartWork改名也都可以对其进行隔离,这个就是个人爱好了。MasterEvent这个特质表示master收到某个命令或事件进行响应的事件,同样也是master发出的。

  上一段话中,我用红色字体标志出了“发出”二字。这意味着,不管是命令还是事件,都是针对发送actor而言的。具体什么意思呢?这其实是一个代码设计的问题,但我觉得比较重要,这里需要单独解释一下。我们知道actor之间是通过消息传递来通信的,那么消息传递一个有一个发送方和接收方。在设计代码时,我们是把消息放到发送方的域中,还是放到接收方的域中呢。比如StartWork这个命令,如果放到masterActor中,就意味着master发出了一个StartWork这个命令,具体是谁收到该消息就不关心了,接收方一定知道该消息是masterActor发出的。如果放到workActor中,就意味着workActor一定会接收该命令,对其作出反应,具体是谁发送的就不关心了。对于事件可以做类比理解。

  具体是按照发送方还是按照接收方封装消息,这个就仁者见仁智者见智了,只不过我比较推崇上面代码中的设计方案。因为我们可以围绕actor设计上下文边界,不会对其他领域内的对象进行引用,高内聚低耦合。

  其实我们还可以通过消息名称来区分,比如有两个actor都会发出StartWork的消息,那么可以分别用StartType1Work和StartType2Work来命令。但这种方式有个问题就是没法按照类型对不同的命令进行筛选,比如我们可以使用match来对不同类型的消息进行过滤,如果消息是用消息名称进行区分的,在偏函数或者match时是很不方便的,关于这一点希望大家自己好好体会。

  其实对于上图中的代码,我一般都会优化成下面的形式。就是把master相关的命令和事件上面再加一个抽象层:master消息。其实都差不多,只不过层次更深而已。优点是可以单独修改公共字段或方法,缺点是设计复杂。

trait Message{
// 消息创建的时间
final val at:Long = System.currentTimeMillis()
}
trait Command extends Message
trait Event extends Message trait MasterMessage extends Message{
// 定义Master消息共有的方法或字段
} trait MasterCommand extends MasterMessage with Command{
// 定义MasterCommand公有的方法或字段
}
trait MasterEvent extends MasterMessage with Event{
// 定义MasterEvent公有的方法或字段
} object MasterCommand{
case class StartWork(message:String) extends MasterCommand
} object MasterEvent{
case class WorkStarted(message:String) extends MasterCommand
}

  关于Akka消息的设计模式就介绍到这里了,在Akka中消息设计的好坏往往决定着应用的质量,希望大家多多实践,多多体会。当然了每个人的设计理念不同,这里也只是抛砖引玉,如果你有更好的设计模式,欢迎留言讨论。

akka设计模式系列-消息模型的更多相关文章

  1. akka设计模式系列-消息模型(续)

    在之前的akka设计模式系列-消息模型中,我们介绍了akka的消息设计方案,但随着实践的深入,发现了一些问题,这里重新梳理一下设计方法,避免之前的错误.不当的观点给大家带来误解. 命令和事件 我们仍然 ...

  2. akka设计模式系列-慎用ask

    慎用ask应该是Akka设计的一个准则,很多时候我们应该禁用ask.之所以单独把ask拎出来作为一篇博文,主要是akka的初学者往往对ask的使用比较疑惑. "Using ask will ...

  3. akka设计模式系列

    由于本人爱好Scala,顺便也就爱好Akka,但目前网上对Akka的介绍大多都是概念上或技术方向上的介绍,基本没有Akka设计模式或者Actor模型设计模式的资料.这对于Akka的普及非常不利,因为即 ...

  4. akka设计模式系列(Actor模型)

    谈到Akka就必须介绍Actor并发模型,而谈到Actor就必须看一篇叫做<A Universal Modular Actor Formalism for Artificial Intellig ...

  5. akka设计模式系列-While模式

    While模式严格来说是while循环在Akka中的合理实现.while是开发过程中经常用到的语句之一,也是绝大部分编程语言都支持的语法.但while语句是一个循环,如果循环条件没有达到会一直执行wh ...

  6. akka设计模式系列-Backend模式

    上一节我们介绍了Akka使用的基本模式,简单点来说就是,发消息给actor,处理结束后返回消息.但这种模式有个缺陷,就是一旦某个消息处理的比较慢,就会阻塞后面所有消息的处理.那么有没有方法规避这种阻塞 ...

  7. akka设计模式系列-actor锚定

    actor锚定模式是指使用actorSelection对acor进行锚定的设计模式,也可以说是一个对actor的引用技巧.在某些情况下,我们可能需要能够根据Actor的path锚定对应的实例.简单来说 ...

  8. akka设计模式系列-Chain模式

    链式调用在很多框架和系统中经常存在,算不得上是我自己总结的设计模式,此处只是简单介绍在Akka中的两种实现方式.我在这边博客中简化了链式调用的场景,简化后也更符合Akka的设计哲学. trait Ch ...

  9. akka设计模式系列-akka在秒杀场景的应用

    本博客讨论一下akka在秒杀场景下的应用,提出自己的见解,只做抛砖引玉,大神勿喷.秒杀活动涉及到前中后台各个阶段,为了说明问题,我们简化场景,只研究akka在后台如何处理秒杀业务. 秒杀活动 所谓的秒 ...

随机推荐

  1. [Luogu] P3701 「伪模板」主席树

    题目背景 byx和手气君都非常都非常喜欢种树.有一天,他们得到了两颗奇怪的树种,于是各自取了一颗回家种树,并约定几年后比一比谁种出来的树更加牛x. 题目描述 很快,这棵树就开花结果了.byx和手气君惊 ...

  2. Spring 工厂方法创建Bean 学习(三)

    1, 静态工厂方法创建Bean 调用静态工厂方法创建 Bean是将对象创建的过程封装到静态方法中. 当客户端需要对象时, 只需要简单地调用静态方法, 而不同关心创建对象的细节. 要声明通过静态方法创建 ...

  3. enum 的使用

    public enum Color { RED(), GREEN(), BLANK(), YELLO(); // 成员变量 private String name; private int index ...

  4. 【Codeforces 486C】Palindrome Transformation

    [链接] 我是链接,点我呀:) [题意] 光标一开始在p的位置 你可以用上下左右四个键位移动光标(左右)或者更改光标所在的字符(上下增加或减少ascill码) 问你最少要操作多少次才能使得字符串变成回 ...

  5. 这个贴子的内容值得好好学习--实例详解Django的 select_related 和 prefetch_related 函数对 QuerySet 查询的优化

    感觉要DJANGO用得好,ORM必须要学好,不管理是内置的,还是第三方的ORM. 最最后还是要到SQL.....:( 这一关,慢慢练啦.. 实例详解Django的 select_related 和 p ...

  6. HDU1914(稳定婚姻)

    http://acm.hdu.edu.cn/showproblem.php?pid=1914 思路:Gale-Shapley算法.算法过程是男士不停地求婚,女士不停地拒绝.在每一轮中,每个尚未订婚的男 ...

  7. T5090 众数 codevs

    http://codevs.cn/problem/5090/ 时间限制: 1 s  空间限制: 1000 KB  题目等级 : 青铜 Bronze 题目描述 Description 由文件给出N个1到 ...

  8. 深度优先遍历DFS

    深度优先遍历,这个跟树中的遍历类似,做深度遍历就是访问一个节点之后,在访问这个节点的子节点,依次下去是一个递归的过程. 具体代码: void DFS(MGraph g ,int i) {     in ...

  9. NETCore项目报错 An error occurred while starting the application

    在发布到IIS的webApi项目中,运行时报出以上错误, 解决方法: 1.打开发布目录文件夹,找到web.config文件 2.打开web.config找到stdoutLogEnabled=" ...

  10. 【python】蛋疼的中文乱码解决方案

    转自: http://yooooo.us/2013/python-encoding-decoding?variant=zh-cn