Kotlin设计模式: Flyweight(享元)模式

程序员咋不秃头2024-05-13 14:12:16  92

享元模式的目的

这个模式主要用于在应用中平衡内存使用。这一切都与对象的可重用性有关(注意是对象,而不是类)。与其每次都创建新对象,不如有一个类似对象的池子可以重用。 这样,你不必每次创建对象时都分配内存,而是一次分配并重用以前创建的对象。

这意味着会节省一些CPU和内存的创建,并让垃圾回收更快。但是,存在权衡。根据实现的不同:

? 控制从池中移除对象,可能会棘手,因为如果你移除当前使用的对象,会破坏调用。

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

两种方法都有缺点,根据你的需要选择一种。如果有什么不清楚的,下面的例子应该会使它更容易理解:

例子

应用在同一屏幕的多个地方使用同一张图片。启动应用程序,结果它因为 OutOfMemoryError 崩溃了。图片已经压缩,无法更小。必须想办法如何节省更多内存。

这是一个完美的Flyweight使用案例,假设有3张图片,每张5MB,总共需要15MB,但使用Flyweight的话,它们只需要5MB。

此外,从网上通过URL获取图片,这里使用Flyweight也会节省时间并限制互联网消耗。

在享元模式中,通常称创建类为工厂(Factory)。应用程序将依赖于 Image 和 ImageFactory,使用 Image 模型,但通过 ImageFactory 创建它们。

data class Image(val bytes: ByteArray)class ImageFactory { private val cache = mutableMapOf suspend fun get(url: String): Image { val cachedImage = cache[url] return if (cachedImage == null) { // 替换为你的抓取方法 val fetchedImage = fetchImage(url) cache[url] = fetchedImage fetchedImage } else { cachedImage } }}

如你所见,享元模式的实现相当简单。这是如何使用它的:

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个请求,这不是我们想要的。因为,在第一次 fetchImage(url) 结束之前,另一个协程尝试从缓存中获取URL,但由于它尚未出现,它也会调用 fetchImage(url)。

可以通过多种方式解决这个问题。下面将展示使用互斥锁(Mutex)的方法,它的工作方式与享元本身类似:

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 { val cachedImage = cache[url] return if (cachedImage == null) { // 替换为你的抓取方法 val fetchedImage = fetchImage(url) cache[url] = fetchedImage fetchedImage } else { cachedImage } }}

转载此文是出于传递更多信息目的。若来源标注错误或侵犯了您的合法权益,请与本站联系,我们将及时更正、删除、谢谢。
https://www.414w.com/read/498095.html
0
最新回复(0)