Apa yang dimaksud dengan layanan stateful dalam kasus ini?
Apakah maksud Anda bahwa itu akan mengeksekusi efek samping ketika suatu objek dibangun?
Untuk ini, ide yang lebih baik adalah memiliki metode yang menjalankan efek samping ketika aplikasi Anda mulai. Alih-alih menjalankannya selama konstruksi.
Atau mungkin Anda mengatakan bahwa ia memiliki status yang bisa berubah di dalam layanan? Selama keadaan bisa berubah internal tidak terkena, itu harus baik-baik saja. Anda hanya perlu memberikan metode murni (transparan referensial) untuk berkomunikasi dengan layanan.
Untuk memperluas poin kedua saya:
Katakanlah kita sedang membangun di memori db.
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, ini tidak perlu efektif, karena hal yang sama terjadi jika Anda melakukan panggilan jaringan. Meskipun, Anda perlu memastikan bahwa hanya ada satu instance dari kelas ini.
Jika Anda menggunakan Ref
efek kucing, apa yang biasanya saya lakukan, adalah ke flatMap
ref pada titik masuk, sehingga kelas Anda tidak harus efektif.
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, jika Anda menulis layanan bersama atau perpustakaan yang bergantung pada objek stateful (katakanlah beberapa concurrency primitif) dan Anda tidak ingin pengguna Anda peduli apa yang harus diinisialisasi.
Maka, ya, itu harus dibungkus dalam suatu efek. Anda dapat menggunakan sesuatu seperti, Resource[F, MyStatefulService]
untuk memastikan bahwa semuanya sudah ditutup dengan benar. Atau hanya F[MyStatefulService]
jika tidak ada yang ditutup.
delay
dan mengembalikan F [Layanan] . Sebagai contoh, lihatstart
metode pada IO , ia mengembalikan IO [Fiber [IO,?]] , Bukan serat polos .