この場合、ステートフルサービスは何を指しますか?
オブジェクトが構築されるときに副作用を実行するということですか?
このため、アプリケーションの起動時に副作用を実行するメソッドを用意することをお勧めします。構築中に実行する代わりに。
それとも、サービス内で変更可能な状態を保持していると言っているのでしょうか?内部の変更可能な状態が公開されていない限り、問題はありません。サービスと通信するための純粋な(参照透過)メソッドを提供する必要があるだけです。
私の2番目のポイントを拡張するには:
メモリ内データベースを構築しているとしましょう。
class InMemoryDB(private val hashMap: ConcurrentHashMap[String, String]) {
def getId(s: String): IO[String] = ???
def setId(s: String): IO[Unit] = ???
}
object InMemoryDB {
def apply(hashMap: ConcurrentHashMap[String, String]) = new InMemoryDB(hashMap)
}
IMO、これは効果的である必要はありません。ネットワーク呼び出しを行った場合も同じことが起こるからです。ただし、このクラスのインスタンスが1つだけであることを確認する必要があります。
Ref
from cats-effect を使用している場合、私が通常行うのflatMap
はエントリポイントのref に対するものであるため、クラスは効果的である必要はありません。
object Effectful extends IOApp {
class InMemoryDB(storage: Ref[IO, Map[String, String]]) {
def getId(s: String): IO[String] = ???
def setId(s: String): IO[Unit] = ???
}
override def run(args: List[String]): IO[ExitCode] = {
for {
storage <- Ref.of[IO, Map[String, String]](Map.empty[String, String])
_ = app(storage)
} yield ExitCode.Success
}
def app(storage: Ref[IO, Map[String, String]]): InMemoryDB = {
new InMemoryDB(storage)
}
}
ステートフルオブジェクト(複数の同時実行プリミティブとしましょう)に依存する共有サービスまたはライブラリを作成していて、ユーザーが何を初期化するかを気にしたくない場合は、OTOH。
そして、はい、それは効果に包まれる必要があります。Resource[F, MyStatefulService]
すべてが適切に閉じられていることを確認するようなものを使用できます。またはF[MyStatefulService]
、閉じるものが何もない場合。
delay
、F [Service]を返す必要があります。例として、IOのstart
メソッドを参照してください。プレーンファイバーの代わりにIO [Fiber [IO、?]]を返します。