持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第19天,点击查看活动详情
- 本文主要介绍iOS设计模式中的
享元模式
,享元模式顾名思义就是通过共享元素
来节约内存,节省储存空间
。
1. 什么是享元模式
比如我们的公共交通已经有一百多年历史了,大量去往相同方向的乘客可以分担车辆的费用
。公共交通设有多个车站。乘客沿者路线在接近他们目的地的地方上下车。到达目的地的费用仅与路程有关。跟保有车辆相比,乘坐公共交通要便宜很多。这就是利用公共资源
的好处。
假如你希望在长时间工作后放松一下, 所以开发了一款简单的游戏: 玩家们在地图上移动并相互射击。 你决定实现一个真实的粒子系统
, 并将其作为游戏的特色。 大量的子弹
、 导弹和爆炸弹片会在整个地图上穿行, 为玩家提供紧张刺激的游戏体验。对于这些子弹的对象他们外表基本相似,只是位置不同。这个时候我们共享
几个子弹的样式
,则会大量减少我们持有的对象数量减少内存消耗
。
我们经常使用的打车软件
,地图上会显示很多车辆
,可以发现车型就那么几种只是车辆的状态或者位置
不同,如果软件地图上有大量的车辆对象,势必造成卡顿,影响用户体验,这时候使用享元模式
。通过一个缓存池保存我们每一种车辆对象,外部计算车辆位置等状态。根据数据从缓存池子
中取出我们要的对象,添加状态
。
实现享元模式要2个关键组件,通常是可共享的享元对象
和保存他们
的池。某种中央对象
维护这个池,并从它返回适当的实例。工厂是这一角色的理想候选。它可以通过一个工厂方法
,根据父类
返回各种类型的具体享元对象。各种框架中,这种工厂通常称为“管理器”
,主要目的就是维护
池中的享元对象
,并适当地从中返回
享元对象。
享元模式:运用共享技术有效地支持大量细粒度的对象。
2. 什么时候使用享元模式
以下情况可以考虑使用享元模式
- 应用程序使用
很多对象
- 在内存中保存对象会
影响
内存性能
- 对象的多数
特有状态
(外在状态)可以放到外部而轻量化
- 移除了外在状态后,可以用较少的
共享对象
替代原来的那组对象。 - 应用
不依赖
于对象标识
,因为共享对象不能
提供唯一的标识
。
3. 代码表示
import XCTest
/// The Flyweight stores a common portion of the state (also called intrinsic
/// state) that belongs to multiple real business entities. The Flyweight
/// accepts the rest of the state (extrinsic state, unique for each entity) via
/// its method parameters.
class Flyweight {
private let sharedState: [String]
init(sharedState: [String]) {
self.sharedState = sharedState
}
func operation(uniqueState: [String]) {
print("Flyweight: Displaying shared ((sharedState)) and unique ((uniqueState) state.\n")
}
}
/// The Flyweight Factory creates and manages the Flyweight objects. It ensures
/// that flyweights are shared correctly. When the client requests a flyweight,
/// the factory either returns an existing instance or creates a new one, if it
/// doesn't exist yet.
class FlyweightFactory {
private var flyweights: [String: Flyweight]
init(states: [[String]]) {
var flyweights = [String: Flyweight]()
for state in states {
flyweights[state.key] = Flyweight(sharedState: state)
}
self.flyweights = flyweights
}
/// Returns an existing Flyweight with a given state or creates a new one.
func flyweight(for state: [String]) -> Flyweight {
let key = state.key
guard let foundFlyweight = flyweights[key] else {
print("FlyweightFactory: Can't find a flyweight, creating new one.\n")
let flyweight = Flyweight(sharedState: state)
flyweights.updateValue(flyweight, forKey: key)
return flyweight
}
print("FlyweightFactory: Reusing existing flyweight.\n")
return foundFlyweight
}
func printFlyweights() {
print("FlyweightFactory: I have (flyweights.count) flyweights:\n")
for item in flyweights {
print(item.key)
}
}
}
extension Array where Element == String {
/// Returns a Flyweight's string hash for a given state.
var key: String {
return self.joined()
}
}
class FlyweightConceptual: XCTestCase {
func testFlyweight() {
/// The client code usually creates a bunch of pre-populated flyweights
/// in the initialization stage of the application.
let factory = FlyweightFactory(states:
[
["Chevrolet", "Camaro2018", "pink"],
["Mercedes Benz", "C300", "black"],
["Mercedes Benz", "C500", "red"],
["BMW", "M5", "red"],
["BMW", "X6", "white"]
])
factory.printFlyweights()
/// ...
addCarToPoliceDatabase(factory,
"CL234IR",
"James Doe",
"BMW",
"M5",
"red")
addCarToPoliceDatabase(factory,
"CL234IR",
"James Doe",
"BMW",
"X1",
"red")
factory.printFlyweights()
}
func addCarToPoliceDatabase(
_ factory: FlyweightFactory,
_ plates: String,
_ owner: String,
_ brand: String,
_ model: String,
_ color: String) {
print("Client: Adding a car to database.\n")
let flyweight = factory.flyweight(for: [brand, model, color])
/// The client code either stores or calculates extrinsic state and
/// passes it to the flyweight's methods.
flyweight.operation(uniqueState: [plates, owner])
}
}
复制代码
执行结果
FlyweightFactory: I have 5 flyweights:
Mercedes BenzC500red
ChevroletCamaro2018pink
Mercedes BenzC300black
BMWX6white
BMWM5red
Client: Adding a car to database.
FlyweightFactory: Reusing existing flyweight.
Flyweight: Displaying shared (["BMW", "M5", "red"]) and unique (["CL234IR", "James Doe"] state.
Client: Adding a car to database.
FlyweightFactory: Can't find a flyweight, creating new one.
Flyweight: Displaying shared (["BMW", "X1", "red"]) and unique (["CL234IR", "James Doe"] state.
FlyweightFactory: I have 6 flyweights:
Mercedes BenzC500red
BMWX1red
ChevroletCamaro2018pink
Mercedes BenzC300black
BMWX6white
BMWM5red
复制代码
4. 小结
享元对象可以节约空间主要是减少对象总
数,每个对象可共享
的状态的数量,外在状态
是计算出来还是保存的。共享减少了内在状态
的开销,通过牺牲计算时间
又节省了外在状态
的存储空间
。分享相同的资源以执行任务,可能比使用个人的资源完成同样的事情更加高效
。