• 学习设计模式系列之六:享元模式


    享元模式:

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

    核心实现:

      共享重复的数据。

      使用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
    请按任意键继续. . .
  • 相关阅读:
    linux之查找文件,目录命令
    linux文件操作常用命令
    linux打包解包压缩解压命令
    linux目录操作常用命令
    php读取文件行数方法
    前端入门之——javascript day8 DOM对象(DHTML)
    前端入门之——javascript day8
    前端入门之——css day5 作业。编写一个简单的网页
    前端入门之——css day4
    前端入门之——css day3
  • 原文地址:https://www.cnblogs.com/zanzan101/p/3407425.html
Copyright © 2020-2023  润新知