2

私はキャッシュを持っており、キャッシュからアイテムを取得してアイテムをキャッシュに入れる2つの機能を持っています。機能的な入手方法または更新方法

(キャッシュから)アイテムを取得するときに、キーが存在しない場合、値を入力してその値を返す必要があります。続き

は、ここで私はget(id)機能の単一責任の原則(SRP)に違反していて、サンプルコード

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に違反することなくこれを行うには?私は単に関数をgetOrUpdate(id)に改名することができます。しかし、それを行うためのクリーンな関数型プログラミングの方法はありますか?あなたが達成したい何

答えて

2

あなたは「機能的」ソリューションを目指している場合は、すべてが機能的な世界では不変であるので、あなたは、あなたのキャッシュMapは不変になりたいです。 - マップが更新されると、どのように更新された値でキャッシュを使用しない

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

今、小さなシワがあります:scala.collection.immutable.Mapは、このメソッドを持っていることに注意してください?このためにはインタフェースを変更する必要があります。

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) 
} 

これは、副作用のない機能的なキャッシュを提供します。また、putupsertに変更し、キャッシュエントリを更新する必要があるかどうかを確認します。

1

は、それが既存のオブジェクトのIDを返します(存在する場合)の要素は、存在しない場合は挿入であることを挿入冪等に似ています。どのように関数の名前を付けても、cacheには依然として副作用があることに注意してください。 Scala-wiseのように、collectFirstgetOrElseのようなものを使用すると、構文的にはより良いものになりますが、問題は残ります。 コードワイズ:

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

mutable mapに定義されたgetOrElseUpdate機能が既にあります。

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

私はこれを見たことがない:)素敵なもの。 – sebszyller

関連する問題