首页 Kotlin 正文
  • 本文约1582字,阅读需8分钟
  • 64
  • 0

Kotlin设计模式:Flyweight

摘要

Flyweight模式的目的 该模式主要用于平衡应用中的内存使用情况。这都与对象可重用性有关(请注意,我使用了“对象”一词,而不是“类”)。您有一个可以重复使用的类似对象池,而不是每次都创建新对象。 这样,您不必在每次创建对象时分配内存,而是分配一次内存并重用之前创建的对象。 这意味着您将在对象创建中节省一些CPU和内存,并使垃圾收集速度更快。然而,有一个...

Kotlin设计模式:Flyweight

Flyweight模式的目的

该模式主要用于平衡应用中的内存使用情况。这都与对象可重用性有关(请注意,我使用了“对象”一词,而不是“类”)。您有一个可以重复使用的类似对象池,而不是每次都创建新对象。

这样,您不必在每次创建对象时分配内存,而是分配一次内存并重用之前创建的对象。

这意味着您将在对象创建中节省一些CPU和内存,并使垃圾收集速度更快。然而,有一个权衡。根据实施情况,您必须:

控制从池中删除对象,这可能很棘手,就像您删除当前使用的对象一样,它会破坏东西。

为未使用的对象分配内存。在这种方法中,不会从池中删除对象,这意味着为当前未使用的东西分配内存。

这两种方法都有缺点,根据您的需求选择一种。如果有些事情不清楚,示例应该让这一切更容易理解:

示例:

您的应用程序在同一屏幕上的多个地方使用相同的图像。您启动应用程序,然后......它因OutOfMemoryError而崩溃。图像已经压缩了,它们不能更小。你得想办法节省更多内存。

这是一个完美的用例,对于Flyweight来说,有3张图片,每张大5MB,这意味着它们总共需要15MB,但使用Flyweight它们只需要5MB

此外,您通过URL从网络获取图像,在这里使用Flyweight也将节省时间并限制互联网消耗。

让我们实现它:

Kotlin设计模式:Flyweight

Flyweight,我们通常称创建类为FactoryApplication将取决于ImageImageFactory,因为它将使用Image模型,但通过ImageFactory创建它们。


data class Image(val bytes: ByteArray)

class ImageFactory {

private val cache = mutableMapOf()

private suspend fun getImage(url: String): Image =

        cache[url] ?: fetchImage(url).also { image -> cache[url] = image }

}

如您所见,Flyweight模式的实现非常简单。以下是使用它的方法:


fun main() {

val factory = ImageFactory()

val scope = CoroutineScope(Dispatchers.IO)

    scope.launch {

val image = factory.get("image")

    }

    scope.launch {

val image = factory.get("image")

    }

}

在这个确切的例子中,存在同步问题

然而,有一个陷阱:您对具有相同URL的图像提出2个请求,这不是我们想要的。发生这种情况是因为,在firstfetchImagefetchImage(url)结束之前,另一个Coroutines试图从cache获取URL,但由于它还不存在,它也调用fetchImage(url)

我们可以通过多种方式修复它。我将展示使用Mutex的方式,它的工作原理与Flyweight本身类似:


class ImageFactory {

    private val cache = mutableMapOf()

    private val locks = mutableMapOf()

    private val lock = Mutex()

    suspend fun get(url: String): Image {

        val imageMutex = lock.withLock {

            locks.getOrPut(url) { Mutex() }

        }

        val image = imageMutex.withLock {

            getImage(url)

        }

        locks.remove(url)

        return image

    }

    private suspend fun getImage(url: String): Image =

        cache[url] ?: fetchImage(url).also { image -> cache[url] = image }

}
标签:Flyweight

扫描二维码,在手机上阅读


    评论