2

У меня есть кэш и есть две функции, чтобы получить элемент из кеша и поместить элемент в кеш.Функциональный способ получить или обновить

При получении элемента (из кеша), если ключ не существует, мне нужно заполнить его значением и вернуть это значение.

Ниже приведен пример кода

class CacheComp { 
    cache = Map[String, Foo] 

    get(id): Foo = { 
     // case(id exists) => Return matching Foo 

     // case(id not exists) => Create a Foo and update the cache with created Foo. Then return updated Foo 
    } 

    put(id, Foo) = { 
     // put element to the cache 
    } 
} 

В здесь я нарушая единый принцип ответственности (SRP) из get(id) функции. Как это сделать, не нарушая SRP? Я могу просто переименовать функцию в getOrUpdate(id). Но есть ли какой-нибудь чистый способ программирования?

ответ

2

Если вы стремитесь к «функциональным» решениям, вы хотите, чтобы ваш кэш Map быть неизменен, потому что все неизменны в функциональном мире. Обратите внимание, что scala.collection.immutable.Map имеет этот метод:

override def updated [B1 >: B](key: A, value: B1): Map[A, B1] 

Теперь есть небольшая складка - после того, как карта обновляется, как использовать кэш-память с обновленным значением? Для этого вам нужно изменить свой интерфейс.

type Cache = Map[String, Foo] 

object Cache { 
    def get(id: String, cache: Cache): (Foo, Cache) = cache.get(id) match { 
    case Some(e) => (e,cache) 
    case None => 
     val foo = makeFoo 
     (foo, cache.updated(id, foo)) 
    } 

    def put(id: String, foo: Foo, cache: Cache): Cache = cache.updated(id, foo) 
} 

Это дает вам функциональный кэш без побочных эффектов. Я также должен изменить put на upsert и проверить, нужно ли обновлять запись в кеше.

1

То, что вы хотите достичь, это похоже на идемпотентного вставки что является вставки, если элемент не существует, если она существует вернуть идентификатор существующего объекта. Вы должны иметь в виду, что независимо от того, как вы называете эту функцию, она по-прежнему будет оказывать побочное воздействие на cache. Scala-wise вы могли бы пойти на такие вещи, как collectFirst, getOrElse, чтобы сделать его более удобным, но проблема остается. Code-накрест:

val cache = scala.collection.mutable.Map[String, Foo]() 
def get(id: String): Foo = cache.collectFirst { case(key, foo) if key == id => foo } match { 
    case Some(foo) => foo 
    case None => { 
    val foo = new Foo //dunno what it would be 
    cache += (id -> foo) 
    foo 
    } 
} 
4

Существует уже getOrElseUpdate функция, определенная на mutable map.

val cache = scala.collection.mutable.Map[String, String]() 
cache.getOrElseUpdate("lang", "scala") 
+0

Я никогда не сталкивался с этим :) хороший. – sebszyller