Сериализация Function1 в базу данных - PullRequest
3 голосов
/ 12 января 2012

Я знаю, что невозможно напрямую сериализовать функцию / анонимный класс в базу данных, но каковы альтернативы? Знаете ли вы какой-нибудь полезный подход к этому?

Чтобы представить мою ситуацию: я хочу наградить пользователя "значками" на основе его оценок. Поэтому у меня есть различные типы значков, которые можно легко определить, расширив этот класс:

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

Член-детектор - это функция, которая просматривает список результатов и возвращает true, если пользователь имеет право на значок этого типа.

Проблема в том, что каждый раз, когда я хочу добавить / отредактировать / изменить тип значка, мне нужно отредактировать исходный код, перекомпилировать все это и заново развернуть сервер. Было бы гораздо полезнее, если бы я мог сохранить все экземпляры BadgeType в базе данных. Но как это сделать?

Единственное, что приходит на ум, - это иметь тело функции в виде скрипта (например, Groovy), который оценивается во время выполнения.

Другой подход (который не включает базу данных) может заключаться в том, чтобы каждый тип значка помещался в банку, которую я могу каким-либо образом развернуть в горячем режиме во время выполнения, что, как я полагаю, может работать плагин-системой.

Что вы думаете?

Ответы [ 3 ]

3 голосов
/ 12 января 2012

Мой очень короткий совет заключается в том, что если вы хотите, чтобы это действительно управлялось данными, вам необходимо реализовать правила DSL и интерпретатор. Правила - это то, что сохраняется в базе данных, и интерпретатор берет экземпляр правила и оценивает его по некоторому контексту.

Но в большинстве случаев это излишне. Вам лучше иметь небольшой фрагмент действительного кода Scala, который реализует правило для каждого значка, присваивает им уникальные идентификаторы, а затем сохраняет идентификаторы в базе данных.

например:.

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]] 

... и если вы заинтересованы в подключаемости во время выполнения, попробуйте шаблон поставщика услуг .

1 голос
/ 13 января 2012

Вы можете попробовать и использовать Scala Continuations - они могут дать вам возможность сериализовать вычисления и запускать их позднее или даже на другой машине.

Некоторые ссылки:

Продолжения

Что такое продолжения Scala и зачем их использовать?

Рой - параллелизм с продолжениями Scala

0 голосов
/ 13 января 2012

Сериализация относится к данным, а не к методам. Вы не можете сериализовать функциональность, потому что это файл класса, который предназначен для сериализации, а сериализация объекта сериализует поля объекта.

Итак, как говорит Алекс, вам нужен механизм правил.

Попробуйте это, если хотите что-то довольно простое, основанное на строках, чтобы вы могли сериализовать правила как строки в базе данных или файле:

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

Использование DSL имеет те же проблемы, если вы не интерпретируете или не скомпилируете код во время выполнения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...