swift设计模式-对象池模式
对象池模式( object poo patterm) 是单例模式的一 种变体,它可以为组件提供多个完全相同的 对象,而非单个对象。当你需要管理- -组 表示可互相替代的资源的对象,且要求同一时刻 只允许- 个组件使用同一个对象时,便可使用对象池模式。
1.是什么
对象池模式般用来管理组可重用的对象,以供调用组件使用。组件可以从对象池中获取对象,用它来完成任务,用完之后将对象还给对象池,以满足组件未来的使用需求。-个对象在被分配给某个调用组件之后,其他组件在它返回对象池以前都无法使用它
2.有什么优点
对象池模式将对象的构建过程隐藏,使组件无需了解此过程。同时,对象池模式通过重用机制将对象初始化的高昂成本摊销
3.何时使用
不管是因为需要 使用对象来表示现实世界中的资源,还是因为对象的初始化成本高昂,而需要创建一组完全相同的对象,我们都可以使用对象池模式
4.何时应避免
若需要保证任意时刻只存在 一个对象,则不应使用此模式,而应该使用单例模式。如果对存在的对象使用此模式的数量没有限制,并允许调用组件自行创建实例,也不应该使用此模式,而应该使用本书讲解的其他模式,比如工厂方法模式
5.如何确定是
若能在不创建新实例的情况 下给调用组件分配对象,并且相关对象返回到对象池后可以满足组件的后 否正确实现续请求, 就说明正确地实现了对象池模式了此模式
protocol PoolItem { var canReuse:Bool {get} } class Pool<T> { private var data = [T]() private var arrayQ = DispatchQueue(label: "arrayQ") private let semaphore : DispatchSemaphore private var itemCount:Int = 0 private let maxItemCount :Int private let itemFactory:() -> T private var ejectedItems = 0 private var poolExhausted = false init(maxItemCount:Int,factory:@escaping () -> T) { self.maxItemCount = maxItemCount self.itemFactory = factory self.semaphore = DispatchSemaphore(value: maxItemCount) } func getFromPool(maxWaitSecond:Int) -> T? { var result :T? let timeOut = DispatchTime.now() + .seconds(maxWaitSecond) if !poolExhausted{ if semaphore.wait(timeout: timeOut) == .success{ if !poolExhausted{ arrayQ.sync {//同步,执行完block,才执行result if self.data.count == 0 && self.itemCount < maxItemCount{ result = self.itemFactory() self.itemCount += 1 }else{ result = self.data.removeFirst() } } } } } return result } func returnToPool(item:T) { arrayQ.async { if let pitem = item as? PoolItem{ if pitem.canReuse{ self.data.append(item) self.semaphore.signal() }else{ self.ejectedItems += 1 if self.ejectedItems == self.maxItemCount { self.poolExhausted = true self.flushQueue() } } }else{ self.data.append(item) } } } //GCD信号量并未提供唤醒所有等待线程的方式,使用以下方式唤醒 func flushQueue() { let dQueue = DispatchQueue(label: "dQueue", attributes: .concurrent) var backLogCleared = false dQueue.async { self.semaphore.wait() backLogCleared = true } //cgd信号量让所有等待的线程以先进先出的方式唤醒执行,也就说,在前边等待的请求通过之前,GCD不会让上边这个闭包执行 //下边这个闭包反复的发出信号量,直到backlogCleared值发生变化,这样就唤醒了所有等待的线程 dQueue.async { while !backLogCleared { self.semaphore.signal() } } } func processPoolItems(callback:([T]) -> Void){ arrayQ.sync(flags: .barrier) { callback(self.data) } }