Swift 实战-享元模式

MolJudkins 6年前
   <p><img src="https://simg.open-open.com/show/eb2be51211dafdda008790423d2e9516.png"></p>    <p>设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。GoF提出了23种设计模式,本系列将使用Swift语言来实现这些设计模式</p>    <h2><strong>概述</strong></h2>    <p>通过共享已存在的对象,减少创建对象内存开销的设计模式被称作 享元模式</p>    <p>享元模式 Flyweight 和单例模式 Singleton 像是一对孪生兄弟,二者的表现方式非常相似,但二者的存在目的却不一样:</p>    <ul>     <li> <p>单例模式<br> 保证了整个应用声明周期内,同一个对象只会存在一份内存,并且任何时间都能被访问使用。</p> <p><img src="https://simg.open-open.com/show/312a30d9f3afd69b63f57d0f85b80bd4.jpg"></p> </li>     <li> <p>享元模式<br> 如果存在可以复用的对象,那么对象将被共享而不是创建新的对象</p> <p><img src="https://simg.open-open.com/show/fab5c770673e4a2ad1d5f7324c894d46.jpg"></p> </li>    </ul>    <p>在iOS开发中,享元模式的最佳实践就是 UITableView 的复用机制——超出屏幕外的单元格统一被回收放到一个复用队列之中,等待着需要新的单元格时进行复用。</p>    <h2><strong>实战</strong></h2>    <p>笔者最近项目有一个需求,几乎所有的数据都要保存在本地。由于应用的特殊性,模块之间需要用到彼此的数据,如果使用单例模式来做,那么同一时间占用的内存是非常的大的,因此以享元模式的思想封装了一个数据管理类:</p>    <pre>  <code class="language-swift">class DataManager {      //MARK: - Variable      private static var shareStorage = [String: AnyObject]()      private var storeKey = "DefaultKey"      private var storeData = [AnyObject]()      var data: [AnyObject] {          get {              return storeData          }      }         //MARK: - Operate      funcinsert(data: AnyObject) { }      funcdelete(atindex: Int) { }      funcsave() { }  }  </code></pre>    <p>笔者以数据模型的类名作为数据管理的关键字,因此创建一个私有的静态字典用来保存当前正在使用的数据。由于数据以加密的方式存储在沙盒目录下,在数据量足够大的时候,从本地读取这些数据会占用大量的花销,因此在数据管理对象被创建的时候需要判断是否存在可复用的数据,如果不存在再从本地加载:</p>    <pre>  <code class="language-swift">class DataManager {      init() {          initalizeData()      }         init(storeKey: String) {          self.storeKey = storeKey          initalizeData()      }         private funcinitalizeData() {          if letdata = DataManager.shareStorage[storeKey] {              storeData = dataas! [AnyObject]          } else {              loadData()              DataManager.shareStorage[storeKey] = storeDataas AnyObject?          }      }         private funcloadData() {          //  load data from local path      }  }  </code></pre>    <p>ok,对于数据的复用已经完成了,剩下的问题是不可能让字典一直存储这些数据,否则直接使用单例要更加方便的多。对此,笔者使用了计数功能,保证数据可以在没有使用的时候进行本地存储然后释放:</p>    <pre>  <code class="language-swift">class DataManager {         deinit {          letcount = DataManager.shareStorage[countKey()] as! Int          if count == 1 {              save()              DataManager.shareStorage[storeKey] = nil          } else {              DataManager.shareStorage[countKey()] = (count - 1) as AnyObject?          }      }         private funcinitalizeData() {          if letdata = DataManager.shareStorage[storeKey] {              letcount = DataManager.shareStorage[countKey()] as! Int              DataManager.shareStorage[countKey()] = (count + 1) as AnyObject?              storeData = dataas! [AnyObject]          } else {              loadData()              DataManager.shareStorage[countKey()] = 1 as AnyObject              DataManager.shareStorage[storeKey] = storeDataas AnyObject?          }      }         private funccountKey() -> String {          return "\(storeKey)Count"      }  }  </code></pre>    <p>上面的代码是初步的逻辑搭建,下一步还需要考虑线程安全等其他问题,这里就不再写出来了</p>    <h2><strong>总结</strong></h2>    <p>最开始接触享元模式概念的时候,笔者是有些混乱的,也不清楚它和单例的区别。简单来说,这是一种提供了一种拥有单例优点、以及改善了一部分单例缺点的设计模式,但是享元模式更加的复杂,在考虑到多线程的环境下,数据竞争要比单例激烈的多,也危险的多。</p>    <p> </p>    <p>来自:http://ios.jobbole.com/89526/</p>    <p> </p>