享元模式:ios
在設計實現包含大量對象的數據結構時,考慮將對象劃分爲可共享的部分和不可共享的部分,其中可共享的部分共享存儲,不可共享的部分單獨存儲,從而節約存儲空間。數據結構
核心實現:函數
共享重複的數據。大數據
使用hash_table、set等集合,有效的管理動畫
本質上是一種壓縮,是一種處理大數據的方式。spa
適用場景:設計
對象個數極多code
對象之間的重複屬性特別多對象
經常使用於富格式文本的存儲blog
舉例說明:
一個地圖中,有不少不少用於裝飾的植物,如花朵、草叢、仙人掌等等,衆多的植物每個都是一個對象,每一個植物對象都有顏色、高度、座標、當前幀、動畫貼圖等等,其中動畫貼圖將佔據大量的內存空間。若是不使用享元模式,將會因爲大量的重複數據而形成浪費,以下圖:
圖 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 請按任意鍵繼續. . .