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

享元模式:

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

核心实现:

  共享重复的数据。

  使用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
请按任意键继续. . .
原文地址:https://www.cnblogs.com/zanzan101/p/3407425.html