學習設計模式系列之五:原型模式

原型模式: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
請按任意鍵繼續. . .
相關文章
相關標籤/搜索