网站首页 > 文章精选 正文
享元模式的目的
这个模式主要用于在应用中平衡内存使用。这一切都与对象的可重用性有关(注意是对象,而不是类)。与其每次都创建新对象,不如有一个类似对象的池子可以重用。 这样,你不必每次创建对象时都分配内存,而是一次分配并重用以前创建的对象。
这意味着会节省一些CPU和内存的创建,并让垃圾回收更快。但是,存在权衡。根据实现的不同:
- o 控制从池中移除对象,可能会棘手,因为如果你移除当前使用的对象,会破坏调用。
- o 为未使用的对象分配内存。在这种方法中不删除池中的对象,这意味着为当前未使用的东西分配内存。
两种方法都有缺点,根据你的需要选择一种。如果有什么不清楚的,下面的例子应该会使它更容易理解:
例子
应用在同一屏幕的多个地方使用同一张图片。启动应用程序,结果它因为 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<String, Image>()
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<String, Image>()
private val locks = mutableMapOf<String, Mutex>()
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
}
}
}
猜你喜欢
- 2025-07-17 阿里云短视频 SDK For Android 快速接入
- 2025-07-17 谈谈 Unsafe 在 Java 中的作用(unsafe_unretained)
- 2025-07-17 Spring Native 中文文档(spring文档中文版)
- 2025-07-17 Java线程池ThreadPoolExecutor实现原理剖析
- 2025-07-17 以后我准备告别String.format()了,因为它不够香!
- 2025-07-17 你真的了解java中的泛型吗?(java的泛型及实现原理)
- 2025-07-17 框架拦截器的秘密:责任链模式全解析!
- 2025-07-17 MapStruct架构设计(mapstruct官方文档)
- 2025-07-17 迭代器模式进阶:遍历数据时,为何不能修改集合?
- 2025-07-17 工厂、建造者、装饰器、适配器:解密JDK设计模式的实战妙用
- 最近发表
- 标签列表
-
- newcoder (56)
- 字符串的长度是指 (45)
- drawcontours()参数说明 (60)
- unsignedshortint (59)
- postman并发请求 (47)
- python列表删除 (50)
- 左程云什么水平 (56)
- 编程题 (64)
- postgresql默认端口 (66)
- 数据库的概念模型独立于 (48)
- 产生系统死锁的原因可能是由于 (51)
- 数据库中只存放视图的 (62)
- 在vi中退出不保存的命令是 (53)
- 哪个命令可以将普通用户转换成超级用户 (49)
- noscript标签的作用 (48)
- 联合利华网申 (49)
- swagger和postman (46)
- 结构化程序设计主要强调 (53)
- 172.1 (57)
- apipostwebsocket (47)
- 唯品会后台 (61)
- 简历助手 (56)
- offshow (61)
- mysql数据库面试题 (57)
- fmt.println (52)