zoukankan      html  css  js  c++  java
  • 学习设计模式系列之六:享元模式

    享元模式:

      在设计实现包含大量对象的数据结构时,考虑将对象划分为可共享的部分和不可共享的部分,其中可共享的部分共享存储,不可共享的部分单独存储,从而节约存储空间。

    核心实现:

      共享重复的数据。

      使用hash_table、set等集合,有效的管理

      本质上是一种压缩,是一种处理大数据的方式。

    适用场景:

      对象个数极多

      对象之间的重复属性特别多

      常用于富格式文本的存储

    举例说明:

      一个地图中,有很多很多用于装饰的植物,如花朵、草丛、仙人掌等等,众多的植物每一个都是一个对象,每个植物对象都有颜色、高度、坐标、当前帧、动画贴图等等,其中动画贴图将占据大量的内存空间。如果不使用享元模式,将会由于大量的重复数据而造成浪费,如下图:

     

    图 1 非享元模式

      而使用享元模式,则可以有效的管理重复内存,从而节约空间,如下图:

     

    图 2 享元模式

    代码:

      1 #include <memory>
      2 #include <hash_map>
      3 #include <string>
      4 #include <iostream>
      5 
      6 /***
      7 * @author:zanzan101
      8 */
      9 
     10 using namespace std;
     11 
     12 // 模拟图像数据的存储结构
     13 class ImageData
     14 {
     15 private:
     16     char* _name;
     17     char _data[100];
     18 public:
     19     ImageData(const char* name):_name(0)
     20     {
     21         _name = 0;
     22         _name = new char[strlen(name)+1];
     23         strcpy(_name, name);
     24         memset(_data, 0, sizeof(_data));
     25     }
     26 
     27     static ImageData load_image(const char* name)
     28     {
     29         return ImageData(name);
     30     }
     31 
     32     bool operator==(const char* name) const
     33     {
     34         return string(_name) == string(name);
     35     }
     36 
     37     const char* get_image_name() const {return _name;}
     38 
     39 };
     40 
     41 class Plant
     42 {
     43 private:
     44     int _pos_x;
     45     int _pos_y;
     46     char* _image_name;
     47 public:
     48     Plant(const char* name):_pos_x(0), _pos_y(0), _image_name(0)
     49     {
     50         _image_name = new char[strlen(name)+1];
     51         strcpy(_image_name, name);
     52     }
     53     int get_pos_x(){return _pos_x;}
     54     int get_pos_y(){return _pos_y;}
     55     const char* get_image_name(){return _image_name;}
     56 };
     57 
     58 class Map
     59 {
     60 private:
     61     // 存储“内部状态”,即:不同对象可以共享的数据,共性的数据
     62     vector<ImageData> _image_data;
     63 
     64     // 存储“外部状态”,即:与环境相关,不同对象不能共享的数据,有个性的数据
     65     vector<Plant> _plant;
     66 public:
     67     void add_plant(const char* name)
     68     {
     69         _plant.push_back(Plant(name));
     70         for(int i = 0; i < _image_data.size(); i++)
     71             if (_image_data[i] == name)
     72                 return;
     73         _image_data.push_back(ImageData::load_image(name));
     74     }
     75     void render_image(const ImageData& image_data, int pos_x, int pos_y)
     76     {
     77         // 绘制图像
     78         // 注意:这里的image_data是const类型的,调用的函数必须也是const的类型的
     79         cout<< "render a plant : " << image_data.get_image_name() <<endl;
     80     }
     81 
     82     // 绘制一棵植物,这里综合用到了共享数据和私有数据
     83     void render_plant(Plant& plant)
     84     {
     85         vector<ImageData>::iterator iter;
     86         for(iter = _image_data.begin(); iter != _image_data.end(); iter++)
     87             if(*iter == plant.get_image_name())
     88                 break;
     89         if(iter != _image_data.end())
     90             render_image(*iter, plant.get_pos_x(), plant.get_pos_y());
     91     }
     92 
     93     // 绘制所有的植物
     94     void render()
     95     {
     96         for(int i = 0; i < _plant.size(); i++)
     97             render_plant(_plant[i]);
     98     }
     99 
    100     // 获取当前的存储对象的信息
    101     void info()
    102     {
    103         cout<< "num of plants : "<< _plant.size() << endl;
    104         cout<< "num of images : "<< _image_data.size() << endl;
    105     }
    106 };
    107 
    108 int _tmain(int argc, _TCHAR* argv[])
    109 {    
    110     Map m;
    111 
    112     // 添加大量植物对象
    113     m.add_plant("草丛");
    114     m.add_plant("草丛");
    115     m.add_plant("草丛");
    116     m.add_plant("草丛");
    117     m.add_plant("仙人掌");
    118     m.add_plant("仙人掌");
    119     m.add_plant("仙人掌");
    120     m.add_plant("草丛");
    121     m.add_plant("草丛");
    122     m.add_plant("草丛");
    123     m.add_plant("花朵");
    124     m.add_plant("花朵");
    125 
    126     // 访问植物对象
    127     m.render();
    128 
    129     // 输出存储信息
    130     m.info();
    131 
    132     system("pause");
    133     return 0;
    134 }

    输出结果:

    render a plant : 草丛
    render a plant : 草丛
    render a plant : 草丛
    render a plant : 草丛
    render a plant : 仙人掌
    render a plant : 仙人掌
    render a plant : 仙人掌
    render a plant : 草丛
    render a plant : 草丛
    render a plant : 草丛
    render a plant : 花朵
    render a plant : 花朵
    num of plants : 12
    num of images : 3
    请按任意键继续. . .
  • 相关阅读:
    【JAVA笔记——道】JAVA对象销毁
    【JAVA笔记——道】并发编程CAS算法
    httpClientUtil的get请求
    python基础 day11 下 ORM介绍 sqlalchemy安装 sqlalchemy基本使用 多外键关联 多对多关系 表结构设计作业
    python基础 day11 上 数据库介绍 mysql 数据库安装使用 mysql管理 mysql 数据类型 常用mysql命令 事务 索引 python 操作mysql ORM sqlachemy学习
    Python基础 Day10 Gevent协程 SelectPollEpoll异步IO与事件驱动 Python连接Mysql数据库操作 RabbitMQ队列 RedisMemcached缓存 Paramiko SSH Twsited网络框架
    python基础 day9 进程、与线程区别 python GIL全局解释器锁 线程 进程
    python基础 day8 Socket语法及相关 SocketServer实现多并发
    python基础 day7 面向对象高级语法部分 异常处理 异常处理 Socket开发基础
    python基础 day6 面向对象的特性:封装、继承、多态 类、方法、
  • 原文地址:https://www.cnblogs.com/zanzan101/p/3407425.html
Copyright © 2011-2022 走看看