享元模式(Flyweight Pattern)

    典型的享元模式的例子为文书处理器中以图形结构来表示字符。一个做法是,每个字形有其字型外观, 字模 metrics, 和其它格式资讯,但这会使每个字符就耗用上千字节。取而代之的是,每个字符参照到一个共享字形物件,此物件会被其它有共同特质的字符所分享;只有每个字符(文件中或页面中)的位置才需要另外储存。

    示例

    结构图

    时序图
    享元模式 - 图1

    1. class WebSite
    2. {
    3. private string name = "";
    4. private WebSite(string name)
    5. {
    6. this.name = name;
    7. }
    8. public void Use()
    9. {
    10. Console.WriteLine("网站分类" + name);
    11. }
    12. }

    客户端代码

    1. static void Main(string args)
    2. {
    3. WebSite fx = new WebSite("产品展示");
    4. fx.Use();
    5. WebSite fy = new WebSite("产品展示");
    6. fy.Use();
    7. WebSite f1 = new WebSite("博客");
    8. f1.Use();
    9. WebSite f2 = new WebSite("博客");
    10. f2.Use();
    11. Console.Read();
    12. }

    网站抽象类

    1. abstract class WebSite
    2. {
    3. public abstract void Use();
    4. }

    网站工厂类

    1. //网站工厂
    2. class WebSiteFactory
    3. {
    4. private HashTable flyweights = new Hashtable();
    5. //获得网站分类
    6. public WebSite GetWebSiteCategory(string key)
    7. {
    8. flyweights.Add(key, new ConcreteWebSite(key));
    9. return ((WebSite)flyweights[key]);
    10. }
    11. //获得网站分类总数
    12. {
    13. return flyweights.Count;
    14. }
    15. }

    客户端代码

    1. static void Main(string[] args)
    2. {
    3. WebSiteFactory f = new WebSiteFactory();
    4. WebSite fx = f.GetWebSiteCategory("产品展示");
    5. fx.Use();
    6. WebSite fy = f.GetWebSiteCategory("产品展示");
    7. fy.Use();
    8. WebSite f1 = f.GetWebSiteCategory("博客");
    9. f1.Use();
    10. WebSite f2 = f.GetWebSiteCategory("博客");
    11. f2.Use();
    12. }

    实际上,享元模式可以避免大量非常详细类的开销。在程序设计中,有时需要生成大量细力度的类实例来表示数据。如果能发现这些实例除了几个参数外基本上都是相同的,有时就能够受大幅度地减少需要实例化的类的数量。如果能把这些蚕食移到类实例的外面,在方法调用时将它们传递进来,就可以通过共享大幅度地减少单个实例的数目。

    用户类,用于网站的客户端账号,是”网站”类的外部状态

    1. //用户
    2. public class User
    3. {
    4. private string name;
    5. public User(string name)
    6. {
    7. this.name = name;
    8. }
    9. public string name
    10. {
    11. get {return name;}
    12. }
    13. }

    网站抽象类

    具体网站类

    1. class ConcreteWebSite: WebSite
    2. {
    3. private string name = "";
    4. public ConcreteWebSite(string name)
    5. {
    6. this.name = name;
    7. }
    8. public override void Use(Use user)
    9. Console.WriteLine("网站分类:" name + "用户:" + user.name);
    10. }
    1. class WebSiteFactory
    2. {
    3. private Hashtable flyweights = new HashTable();
    4. //获得网站分类
    5. public WebSite GetWebSiteCateegory(string key)
    6. {
    7. if (!flyweights.ContainsKey(key))
    8. flyweights.Add(key, new ConcreteWebSite(key));
    9. return ((webSite)flyweightskey[key]);
    10. }
    11. //获得网站分类总数
    12. public int GetWebSiteCount
    13. {
    14. return flyweights.Count;
    15. }
    16. }

    客户端代码

    1. static void Main(string[] args)
    2. {
    3. WebSiteFactory f = new WebSiteFactory();
    4. WebSite fx = f.GetWebSiteCategory("产品展示");
    5. fx.Use(new User("小菜"));
    6. WebSite fy = f.GetWebSiteCategory("产品展示");
    7. fy.Use(new User("小白"));
    8. WebSite f1 = f.GetWebSiteCategory("博客");
    9. f1.Use(new User("小黑"));
    10. WebSite f2 = f.GetWebSiteCategory("博客");
    11. f2.Use(new User("小绿"));
    12. Console.Read();
    13. }

    如果一个应用程序使用了大量的对象,而大量哒这些对象造成了很大的储存开销时就应该考虑使用;还有就是对象的大多数状态可以外部状态,如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象,此时可以考虑使用享元模式。

    在使用UITableView的时候我们应该熟悉这样的接口:

    在要使用一个Cell的时候我们先去看看tableView中有没有可以重用的cell,如果有就用这个可以重用的cell,只有在没有的时候才去创建一个Cell。这就是享元模式。

    享元模式可以理解成,当细粒度的对象数量特别多的时候运行的代价会相当大,此时运用共享的技术来大大降低运行成本。比较突出的表现就是内容有效的抑制内存抖动的情况发生,还有控制内存增长。它的英文名字是flyweight,让重量飞起来。哈哈。名副其实,在一个TableView中Cell是一个可重复使用的元素,而且往往需要布局的cell数量很大。如果每次使用都创建一个Cell对象,系统的内容抖动会非常明显,而且系统的内存消耗也是比较大的。突然一想,享元模式只是给对象实例共享提供了一个比较霸道的名字吧。

    1. - (DZTableViewCell*) dzTableView:(DZTableView *)tableView cellAtRow:(NSInteger)row
    2. {
    3. static NSString* const cellIdentifiy = @"detifail";
    4. DZTypeCell* cell = (DZTypeCell*)[tableView dequeueDZTalbeViewCellForIdentifiy:cellIdentifiy];
    5. if (!cell) {
    6. cell = [[DZTypeCell alloc] initWithIdentifiy:cellIdentifiy];
    7. }
    8. NSString* text = _timeTypes[row];