原型模式:ios
屬於建立型設計模式,直接複製一個已存在的實例做爲新實例。設計模式
背景補充:函數
建立型的設計模式,都屬於工廠,內部實現產生實例的方法,對外開放一個得到實例的接口,將產生實例的方法與客戶分離,下降耦合度。this
使用原型模式,能夠同時使用單例模式產生工廠實例,使用抽象工廠管理生產線,再使用原型模式返回對象。spa
核心實現:prototype
實現拷貝構造函數。設計
適用場景:3d
實例很是複雜,設置很是麻煩,實例的初始化很是耗時;code
試圖得到實例的客戶並無設置參數的能力,或者不想花費時間去設置參數。對象
模型類圖:
圖 1 模型圖
舉例說明:
在本例中,同時使用了抽象工廠,單例模式和原型模式:
工廠實例是經過單例模式建立的;
客戶須要的Tank實例是經過原型模式實現的;
對於客戶與產品之間的對應是經過抽象工廠模式實現的。
圖 2 舉例類圖
代碼:
1 #include <iostream> 2 #include <vector> 3 #include <stdlib.h> 4 5 /*** 6 * @author:zanzan101 7 */ 8 9 using namespace std; 10 // 定義枚舉類型 11 enum tank_state 12 { 13 TANK_ATTACK, 14 TANK_MOVE, 15 TANK_MOVEATTACK, 16 TANK_GARD, 17 TANK_HOLD 18 }; 19 enum tank_type 20 { 21 PRISMTANK, 22 GRIZZLYTANK, 23 RHINOHEAVYTANK 24 }; 25 // 定義坦克類 26 class Tank 27 { 28 protected: 29 int _hp; 30 int _damage; 31 int _speed; 32 int _state; 33 int _type; 34 int _pos_x; 35 int _pos_y; 36 bool _dead; 37 public: 38 39 // 爲避免派生類對象形成內存泄漏,須要將析構函數設置爲虛函數 40 virtual ~Tank(){} 41 virtual void set_param(int hp, int da, int sp, int st, int ty, int pos_x, int pos_y, bool dead) 42 { 43 _hp = hp; 44 _damage = da; 45 _speed = sp; 46 _state = st; 47 _type = ty; 48 _pos_x = pos_x; 49 _pos_y = pos_y; 50 _dead = dead; 51 } 52 virtual void speaking() const =0; 53 }; 54 55 class PrismTank: public Tank 56 { 57 private: 58 char* _chinese_name; 59 public: 60 PrismTank():_chinese_name(0){} 61 62 // 使用原型模式時,若是類對象不適合用淺拷貝的時候,必須實現深拷貝構造函數,以下所示: 63 PrismTank(PrismTank& tank) 64 { 65 _hp = tank._hp; 66 _damage = tank._damage; 67 _speed = tank._speed; 68 _state = tank._state; 69 _type = tank._type; 70 _pos_x = tank._pos_x; 71 _pos_y = tank._pos_y; 72 _dead = tank._dead; 73 _chinese_name = new char[strlen(tank._chinese_name)+1]; 74 strcpy(_chinese_name, tank._chinese_name); 75 } 76 77 // 因爲本類對象申請了堆內存,爲避免內存泄漏,須要利用多態機制進行析構 78 ~PrismTank() 79 { 80 if(_chinese_name) 81 delete _chinese_name; 82 } 83 void set_param(int hp, int da, int sp, int st, int ty, int pos_x, int pos_y, bool dead, const char* name) 84 { 85 _hp = hp; 86 _damage = da; 87 _speed = sp; 88 _state = st; 89 _type = ty; 90 _pos_x = pos_x; 91 _pos_y = pos_y; 92 _dead = dead; 93 _chinese_name = new char[strlen(name)+1]; 94 strcpy(_chinese_name, name); 95 } 96 void speaking() const 97 { 98 cout<< "I'm a Prism Tank! My chinese name is "<< _chinese_name << " My param are hp: "<< _hp << " damage: "<< _damage <<endl; 99 } 100 }; 101 102 class GrizzlyTank: public Tank 103 { 104 public: 105 // 若是類適合用淺拷貝,則無需實現拷貝構造函數,系統默認的拷貝構造函數就能完成淺拷貝任務。 106 107 void speaking() const 108 { 109 cout<< "I'm a Grizzly Tank! My param are hp: "<< _hp << " damage: "<< _damage <<endl; 110 } 111 }; 112 113 class RhinoHeavyTank: public Tank 114 { 115 public: 116 RhinoHeavyTank(){} 117 118 // 下面實現的拷貝構造函數,但其實際上默認的同樣~ 119 RhinoHeavyTank(RhinoHeavyTank& tank) 120 { 121 memcpy(this, &tank, sizeof(RhinoHeavyTank)); 122 } 123 124 void speaking() const 125 { 126 cout<< "I'm a Rhino Heavy Tank! My param are hp: "<< _hp << " damage: "<< _damage <<endl; 127 } 128 }; 129 130 // 使用單例模式建立工廠的實例 131 class Factory 132 { 133 private: 134 135 // 只有靜態常量數據才能夠在類中直接初始化,例如,下面的初始化是合法的: 136 // static const int nothing = 0; 137 138 // 然而,常量非靜態數據則不能夠直接初始化,例如,下面的初始化是非法的: 139 // const int nothing = 0; 140 141 // 常量非靜態數據須要在「構造函數成員初始值設定項列表」中初始化,例如,下面初始化是合法的: 142 // const int nothing; 143 // Factory(): nothing(0){} 144 145 static Factory* _instance; 146 PrismTank _prism_tank; 147 GrizzlyTank _grizzly_tank; 148 RhinoHeavyTank _rhino_heavy_tank; 149 Factory() 150 { 151 // 初始化原型實例,這一次初始化以後,後面的實例就是由他們進行拷貝構造 152 _prism_tank.set_param(100, 160, 30, TANK_GARD, PRISMTANK, 0, 0, false, "光棱坦克"); 153 _grizzly_tank.set_param(140, 60, 50, TANK_GARD, GRIZZLYTANK, 0, 0, false); 154 _rhino_heavy_tank.set_param(180, 180, 20, TANK_GARD, RHINOHEAVYTANK, 0, 0, false); 155 } 156 157 158 public: 159 // 獲取單例的接口 160 static Factory* get_instance() 161 { 162 if(!_instance) 163 _instance = new Factory(); 164 return _instance; 165 } 166 167 // 使用抽象工廠模式設計的對客戶的接口,即,客戶只需提供型號,而與生產線分離 168 Tank* get_prototype_tank(int type) 169 { 170 switch(type) 171 { 172 // 對於每一種型號,使用原型模式設計對實例的初始化 173 case PRISMTANK: 174 return (Tank*)(new PrismTank(_prism_tank)); 175 case GRIZZLYTANK: 176 return (Tank*)(new GrizzlyTank(_grizzly_tank)); 177 case RHINOHEAVYTANK: 178 return (Tank*)(new RhinoHeavyTank(_rhino_heavy_tank)); 179 default: 180 cout<< "ERROR: wrong type !" << endl; 181 return 0; 182 } 183 } 184 }; 185 Factory* Factory::_instance = 0; 186 187 // 設計客戶 188 class Client 189 { 190 private: 191 Factory* _factory; 192 public: 193 Client() 194 { 195 _factory = Factory::get_instance(); 196 } 197 198 // 模擬演示對原型模式的調用方法 199 void do_something() 200 { 201 Tank* tank; 202 203 // 客戶調用工廠的接口,得到經過原型模式建立的實例 204 tank = _factory->get_prototype_tank(PRISMTANK); 205 tank->speaking(); 206 delete tank; 207 208 tank = _factory->get_prototype_tank(GRIZZLYTANK); 209 tank->speaking(); 210 delete tank; 211 212 tank = _factory->get_prototype_tank(RHINOHEAVYTANK); 213 tank->speaking(); 214 delete tank; 215 // 能夠看出來上面的tank實例都是拷貝自工廠中的成品對象 216 } 217 }; 218 int _tmain(int argc, _TCHAR* argv[]) 219 { 220 Client client; 221 client.do_something(); 222 223 system("pause"); 224 return 0; 225 }
輸出結果:
I'm a Prism Tank! My chinese name is 光棱坦克 My param are hp: 100 damage: 160 I'm a Grizzly Tank! My param are hp: 140 damage: 60 I'm a Rhino Heavy Tank! My param are hp: 180 damage: 180 請按任意鍵繼續. . .