将Function1序列化为数据库

时间:2012-01-12 18:06:21

标签: scala serialization plugins

我知道将函数/匿名类序列化到数据库并不是直接可行的,但有哪些替代方案?你知道有什么有用的方法吗?

提出我的情况:我想根据他的分数奖励用户“徽章”。所以我有不同类型的徽章,可以通过扩展这个类来轻松定义:

class BadgeType(id:Long, name:String, detector:Function1[List[UserScore],Boolean])

检测器成员是一个遍历分数列表的函数,如果用户有资格获得此类徽章,则返回true。

问题是,每次我想添加/编辑/修改徽章类型时,我都需要编辑源代码,重新编译整个内容并重新部署服务器。如果我可以将所有BadgeType实例持久化到数据库,那将会更有用。但是怎么做呢?

唯一想到的是将函数体作为在运行时计算的脚本(例如:Groovy)。

另一种方法(不涉及数据库)可能是将每个徽章类型放入一个jar中,我可以在运行时以某种方式进行热部署,我想这是一个插件系统可能如何工作。

您怎么看?

3 个答案:

答案 0 :(得分:3)

我非常简短的建议是,如果您希望这是真正的数据驱动,您需要实现规则DSL和解释器。规则是保存到数据库的内容,解释器接受规则实例并根据某些上下文对其进行评估。

但大部分时间都是过度杀戮。你最好有一小段实际的Scala代码来实现每个徽章的规则,为它们提供唯一的ID,然后将ID存储在数据库中。

e.g:

trait BadgeEval extends Function1[User,Boolean] {
  def badgeId: Int
}

object Badge1234 extends BadgeEval {
  def badgeId = 1234
  def apply(user: User) = {
    user.isSufficientlyAwesome // && ...
  }
}

您可以拥有BadgeEval实例的大白名单:

val weDontNeedNoStinkingBadges = Map(
  1234 -> Badge1234,
  5678 -> Badge5678,
  // ...
}

def evaluator(id: Int): Option[BadgeEval] = weDontNeedNoStinkingBadges.get(id)

def doesUserGetBadge(user: User, id: Int) = evaluator(id).map(_(user)).getOrElse(false)

...或者如果你想让它们分离,请使用反射:

def badgeEvalClass(id: Int) = Class.forName("com.example.badge.Badge" + id + "$").asInstanceOf[Class[BadgeEval]] 

...如果您对运行时可插拔性感兴趣,请尝试service provider pattern

答案 1 :(得分:1)

您可以尝试使用Scala Continuations - 它们可以让您能够序列化计算并在以后甚至在另一台计算机上运行它。

一些链接:

Continuations

What are Scala continuations and why use them?

Swarm - Concurrency with Scala Continuations

答案 2 :(得分:0)

序列化涉及数据而不是方法。您无法序列化功能,因为它是一个类文件,用于序列化该对象并且对象序列化序列化对象的字段。

就像Alex说的那样,你需要一个规则引擎。

如果你想要一些基于字符串的相当简单的东西,试试这个,所以你可以将规则序列化为数据库或文件中的字符串:

http://blog.maxant.co.uk/pebble/2011/11/12/1321129560000.html

除非您在运行时解释或编译代码,否则使用DSL会遇到同样的问题。