原文地址:Message Guidelines
Akka actor通过不可变消息交流。这些可以在代码的任何地方被定义。因为squbs跨cube处理消息交互,这些消息将被一个消息项目(或者jar)定义,这个项目是这些消息发送者和接受者的依赖。这些消息项目通常有一个单独的文件在单独的包中。
在Scala中,消息必须被不可变的case class或case object定义(不要在你的case class中使用var)。在Java中,消息必须被不可变的Java bean(带有构造函数、只有getter、无sertter)定义。消息通常非常简单并且不包含逻辑。在特定的Scala文件中声明多个消息case class或者case object。除非使用静态匿名内部类,Java类每个文件需要有一个消息类。
Message jar不需要其他依赖。理想情况下,他们都是自给自足的。这些消息的发送者或接受者不应受制于消息引入的附加依赖的影响。
构造消息
参照Scala的case class和case object模式,构造消息是非常简单的并且不需要显式调用构造函数。Case classes 隐式生成一个关联工厂对象通过apply和unapply方法,使他们可以很简单的进行模式转换。不可变的Java bean具备大多数Scala case class的属性。不过,他们的构造需要关键词new
。此外,他们不含 equals()
和hashcode()
的实现。 不过,他们不能使用Sclala的模式匹配和收到限制的Scala模式匹配。对于混合了Java和Scala的实际项目中,推荐Scala case classes(而不是case object) 声明消息。
每当与数据库对象和其他依赖工具与消息集成,通常直接从这些类中提供消息构造。至此,我们必须不能声明相关的工厂对象来提供apply方法来从数据库对象构造消息。这样做将消息会受制于依赖这些database基础(infrastructure)。所有其他使用消息的cube将被这些数据源基础设施依赖影响。
使用message构造的常见模式是使用数据基础设施(或其他)来提供一个 "Message"对象(在cube或package内)。Message对象提供一组apply方法,actor将用来其构造消息,例如从可变数据对象。调用者只需要调用即可从一个对象中构建消息。
Scala:
targetActorRef ! Message(myDBObject)
Java:
targetActorRef.tell(Message.apply(myDBObject), getSelf());
基于基础设置的消息的构造方式将被包含在cube生产这些消息内。这些依赖不会泄露给消息的消费者。
处理复杂的,大的消息
在某些例子中,尤其是处理数据对象,这些对象具有层次结构和重量级构造函数以至于难以存在于简单的case class中。字段的数量已远远超出case class中可能存在的数量,使得它不利于使用模式匹配。复杂消息诸如购买订单、发票可归为此类。这些限制只作用在Scala case class而不是Java bean。
处理这种复杂对象的策略是提供作为特性(trait)的消息来声明所有字段。如果有一个具有层次结构的,子类的类,也应该使用traits继承于父类型的参数类型来呈现。这个在消息项目或jar中完成。
于是,这个在源cube的消息对象将通常声明具体(或抽象)消息实现,通过可变对象中的可变函数。重要的是确保具体或抽象实现提供非功能性的和应该声明额外的字段,除非私有来支持构建。在本质上,它只实现构造函数来创建继承trait的对象。
如果trait或任何扩展trait中定义的字段从其他字段中产生,将被设置在构造实现中,这些字段需要被标记为lazy在初始化过程中避免NullPointerException。这是因为trait在构造中尝试初始化所有的字段。这些被产生的字段引用在构造中尚未被设置。懒加载在第一次使用时将这些字段引用到其他字段,在对象构造之后。
遵循这种模式,消息保持不可变并且消息项目不会添加任何依赖在数据源或其他基础设施,以传递到消息消费者依赖链。