上周温习了代理模式:http://www.cnblogs.com/chinxi/p/7354779.html
在此进行拓展,学习强制代理。但是发现网上大多例子都有个“天坑”(我是这么认为的),在得到代理类之后,真实对象也可以使用自己的方法,绕过了代理,这样使得代理没有了意义。
关于强制代理,字面上意思很清晰,即:
1、只能通过真实对象获取代理类来访问方法
2、其他方法比如直接new 一个代理类 访问方法(不通过本体获取),或是自己通过本体直接调用,都不行
网络上搜到的例子大多是这样的:
1、真实对象有个私有成员,this.proxy,类型为基类的指针
2、真实对象中有方法,在最开始先判断是否为代理
3、判断的方法也很简单,即判断this.proxy是否为空
4、get_proxy的方法也很简单,new出一个代理类赋值给thix.proxy,然后return
网络上搜到的大多数例子是这样的:先用真实对象直接访问方法,再用不通过真实对象得到的代理类访问方法,最后用get_proxy得到的代理类,只有最后一次成功了。乍一看似乎符合强制代理,但细细推敲后发现,至少少了一种情况,就是在通过真实对象得到代理之后,真实对象也可以访问自己的方法了。原因很简单,判断是否为代理的方法,只是判断this.proxy是否为空,而在get_proxy中,已经给this.proxy赋值,此时它非空,真实对象自然可以绕过代理,使用方法了。
用上周的例子,与网络上搜到的方式就是:
车站出了新政策,自己不卖车票,但是可以通过自己想买什么票,得知要去哪里买(代理)。
在上周的类图上做了修改,去掉了Tickets的派生类(简单点....),与Proxy中独有的方法。在此,不把get_proxy方法写进基类,由派生类决定自己是否需要代理。
代理实现,也先用判断_proxy是否为空。最后会有修改版本。
1 /// 2 /// @file Selling_Tickets.h 3 /// @author marrs(chenchengxi993@gmail.com) 4 /// @date 2017-08-13 20:35:28 5 /// 6 7 #ifndef __SELLING_TICKETS_H__ 8 #define __SELLING_TICKETS_H__ 9 10 #include <iostream> 11 12 namespace marrs{ 13 14 using std::cout; 15 using std::endl; 16 using std::string; 17 18 class SellingTickets 19 { 20 public: 21 virtual ~SellingTickets(){} 22 23 public: 24 virtual void Selling() = 0; 25 virtual void Price() = 0; 26 27 }; 28 29 } 30 31 #endif // __SELLING_TICKETS_H__
1 /// 2 /// @file Tickets.h 3 /// @author marrs(chenchengxi993@gmail.com) 4 /// @date 2017-08-13 20:39:17 5 /// 6 7 #ifndef __TICKETS_H__ 8 #define __TICKETS_H__ 9 10 #include "Selling_Tickets.h" 11 12 namespace marrs{ 13 class Proxy; 14 class Tickets 15 : public SellingTickets 16 { 17 public: 18 Tickets(string ticket_type); 19 public: 20 void Selling(); 21 void Price(); 22 23 public: 24 Proxy * Get_Proxy(); 25 26 private: 27 bool Is_Proxy(); 28 29 private: 30 Proxy * _proxy; 31 string _ticket_type; 32 }; 33 34 } 35 36 #endif // __TICKETS_H__
1 /// 2 /// @file Proxy.h 3 /// @author marrs(chenchengxi993@gmail.com) 4 /// @date 2017-08-13 20:46:13 5 /// 6 7 #ifndef __PROXY_H__ 8 #define __PROXY_H__ 9 10 #include "Selling_Tickets.h" 11 12 namespace marrs{ 13 class Tickets; 14 class Proxy 15 : public SellingTickets 16 { 17 public: 18 Proxy(Tickets * ticket); 19 20 public: 21 void Selling(); 22 void Price(); 23 24 private: 25 Tickets * _ticket; 26 27 }; 28 29 } 30 31 #endif // __PROXY_H__
1 /// 2 /// @file Tickets.cc 3 /// @author marrs(chenchengxi993@gmail.com) 4 /// @date 2017-08-19 14:38:00 5 /// 6 7 #include "Tickets.h" 8 #include "Proxy.h" 9 10 namespace marrs{ 11 12 Tickets::Tickets(string ticket_type) 13 : _ticket_type(ticket_type) 14 { 15 16 } 17 18 void Tickets::Selling() 19 { 20 if(Is_Proxy()) 21 { 22 cout << "sell: " << _ticket_type << endl; 23 } 24 } 25 26 void Tickets::Price() 27 { 28 if(Is_Proxy()) 29 { 30 cout << "price: 100 RMB" << endl; 31 } 32 } 33 34 Proxy * Tickets::Get_Proxy() 35 { 36 if(!_proxy) 37 { 38 _proxy = new Proxy(this); 39 } 40 return _proxy; 41 } 42 43 bool Tickets::Is_Proxy() 44 { 45 if(!_proxy) 46 { 47 cout << "please use proxy" << endl; 48 return false; 49 } 50 return true; 51 } 52 53 }
1 /// 2 /// @file Proxy.cc 3 /// @author marrs(chenchengxi993@gmail.com) 4 /// @date 2017-08-19 14:52:18 5 /// 6 7 #include "Proxy.h" 8 #include "Tickets.h" 9 10 namespace marrs{ 11 12 Proxy::Proxy(Tickets * ticket) 13 : _ticket(ticket) 14 { 15 } 16 17 void Proxy::Selling() 18 { 19 _ticket->Selling(); 20 } 21 22 void Proxy::Price() 23 { 24 _ticket->Price(); 25 } 26 27 }
现在,先用前面搜到的例子进行测试:
1 /// 2 /// @file Student.cc 3 /// @author marrs(chenchengxi993@gmail.com) 4 /// @date 2017-08-13 20:51:42 5 /// 6 7 #include "Proxy.h" 8 #include "Tickets.h" 9 10 using namespace marrs; 11 12 int main() 13 { 14 Tickets * ticket = new Tickets("bus_ticket"); 15 ticket->Price(); 16 ticket->Selling(); 17 18 Proxy * proxy = new Proxy(ticket); 19 proxy->Price(); 20 proxy->Selling(); 21 delete proxy; 22 23 proxy = ticket->Get_Proxy(); 24 proxy->Price(); 25 proxy->Selling(); 26 delete proxy; 27 28 delete ticket; 29 30 return 0; 31 }
编译,运行:
[ccx@ubuntu ~/object-oriented/Proxy_Pattern_2]$>g++ * -o main.exe [ccx@ubuntu ~/object-oriented/Proxy_Pattern_2]$>./main.exe please use proxy please use proxy please use proxy please use proxy price: 100 RMB sell: bus_ticket
看着像是强制代理了。好,现在修改一下main:
1 /// 2 /// @file Student.cc 3 /// @author marrs(chenchengxi993@gmail.com) 4 /// @date 2017-08-13 20:51:42 5 /// 6 7 #include "Proxy.h" 8 #include "Tickets.h" 9 10 using namespace marrs; 11 12 int main() 13 { 14 Tickets * ticket = new Tickets("bus_ticket"); 15 Proxy * proxy = ticket->Get_Proxy(); 16 Proxy * proxy_other = new Proxy(ticket); 17 18 proxy->Price(); 19 proxy->Selling(); 20 21 ticket->Price(); 22 ticket->Selling(); 23 24 proxy_other->Price(); 25 proxy_other->Selling(); 26 27 delete proxy; 28 delete ticket; 29 30 return 0; 31 }
[ccx@ubuntu ~/object-oriented/Proxy_Pattern_2]$>g++ * -o main.exe [ccx@ubuntu ~/object-oriented/Proxy_Pattern_2]$>./main.exe price: 100 RMB sell: bus_ticket price: 100 RMB sell: bus_ticket price: 100 RMB sell: bus_ticket
结果完全符合预期,真实对象也可以使用自己的方法了。甚至乱套了,随便来个代理都可以用了。
于是,我对其进行修改,对判断是不是proxy加了点东西:
version 1:
此方法设置了唯一代理
1 /// 2 /// @file Tickets.h 3 /// @author marrs(chenchengxi993@gmail.com) 4 /// @date 2017-08-13 20:39:17 5 /// 6 7 #ifndef __TICKETS_H__ 8 #define __TICKETS_H__ 9 10 #include "Selling_Tickets.h" 11 12 namespace marrs{ 13 class Proxy; 14 class Tickets 15 : public SellingTickets 16 { 17 public: 18 Tickets(string ticket_type); 19 ~Tickets(); 20 public: 21 void Selling(Proxy * proxy); 22 void Price(Proxy * proxy); 23 24 private: 25 void Selling(); 26 void Price(); 27 28 public: 29 Proxy * Get_Proxy(); 30 31 private: 32 bool Is_Proxy(Proxy * proxy) const; 33 34 private: 35 string _ticket_type; 36 Proxy * _proxy; 37 }; 38 39 } 40 41 #endif // __TICKETS_H__
1 /// 2 /// @file Proxy.h 3 /// @author marrs(chenchengxi993@gmail.com) 4 /// @date 2017-08-13 20:46:13 5 /// 6 7 #ifndef __PROXY_H__ 8 #define __PROXY_H__ 9 10 #include "Selling_Tickets.h" 11 12 namespace marrs{ 13 class Tickets; 14 class Proxy 15 : public SellingTickets 16 { 17 public: 18 Proxy(Tickets * ticket); 19 20 public: 21 void Selling(); 22 void Price(); 23 24 private: 25 Tickets * _ticket; 26 27 }; 28 29 } 30 31 #endif // __PROXY_H__
1 /// 2 /// @file Tickets.cc 3 /// @author marrs(chenchengxi993@gmail.com) 4 /// @date 2017-08-19 14:38:00 5 /// 6 7 #include "Tickets.h" 8 #include "Proxy.h" 9 10 namespace marrs{ 11 12 Tickets::Tickets(string ticket_type) 13 : _ticket_type(ticket_type) 14 , _proxy(NULL) 15 { 16 17 } 18 19 Tickets::~Tickets() 20 { 21 if(_proxy) 22 { 23 delete _proxy; 24 } 25 } 26 27 void Tickets::Selling(Proxy * proxy) 28 { 29 if(Is_Proxy(proxy)) 30 { 31 Selling(); 32 } 33 } 34 35 void Tickets::Price(Proxy * proxy) 36 { 37 if(Is_Proxy(proxy)) 38 { 39 Price(); 40 } 41 } 42 43 void Tickets::Selling() 44 { 45 cout << "sell: " << _ticket_type << endl; 46 } 47 48 void Tickets::Price() 49 { 50 cout << "price: 100 RMB" << endl; 51 } 52 53 Proxy * Tickets::Get_Proxy() 54 { 55 if(!_proxy) 56 { 57 _proxy = new Proxy(this); 58 return _proxy; 59 } 60 return NULL; 61 } 62 63 bool Tickets::Is_Proxy(Proxy * proxy) const 64 { 65 if(proxy != _proxy) 66 { 67 cout << "please use proxy" << endl; 68 return false; 69 } 70 return true; 71 } 72 73 }
1 /// 2 /// @file Proxy.cc 3 /// @author marrs(chenchengxi993@gmail.com) 4 /// @date 2017-08-19 14:52:18 5 /// 6 7 #include "Proxy.h" 8 #include "Tickets.h" 9 10 namespace marrs{ 11 12 Proxy::Proxy(Tickets * ticket) 13 : _ticket(ticket) 14 { 15 } 16 17 void Proxy::Selling() 18 { 19 _ticket->Selling(this); 20 } 21 22 void Proxy::Price() 23 { 24 _ticket->Price(this); 25 } 26 27 }
1 /// 2 /// @file Student.cc 3 /// @author marrs(chenchengxi993@gmail.com) 4 /// @date 2017-08-13 20:51:42 5 /// 6 7 #include "Proxy.h" 8 #include "Tickets.h" 9 10 using namespace marrs; 11 12 int main() 13 { 14 Tickets * ticket = new Tickets("bus_ticket"); 15 Proxy * proxy = ticket->Get_Proxy(); 16 17 proxy->Price(); 18 proxy->Selling(); 19 20 Proxy * proxy_other = new Proxy(ticket); 21 proxy_other->Price(); 22 proxy_other->Selling(); 23 24 ticket->Price(proxy); 25 ticket->Selling(proxy); 26 27 ticket->Price(proxy_other); 28 ticket->Selling(proxy_other); 29 30 delete proxy_other; 31 delete ticket; 32 33 return 0; 34 }
1 [ccx@ubuntu ~/object-oriented/Proxy_Pattern_3]$>g++ *.h *.cc -o main.exe 2 [ccx@ubuntu ~/object-oriented/Proxy_Pattern_3]$>./main.exe 3 price: 100 RMB 4 sell: bus_ticket 5 please use proxy 6 please use proxy 7 price: 100 RMB 8 sell: bus_ticket 9 please use proxy 10 please use proxy
这样的话,还有点小问题,就是真实对象可以通过传入代理的指针来访问自己的方法。但是,如果不传参的话,是用不了的。基类的那两个方法,在Ticket中,写进了private。还有,此方法目前缺少一个回收代理的方法。万一另一个地方要用的话,就用不了了。
version 2
version 2 其实就是把传参改成了随机字符串,此字符串在get_proxy中生成,并传入Proxy对象中,只有代理和真实对象知道那是什么。这里就不实现了,跟version 1 差不多的。
version 3
多个代理
此方法只不过是在真实对象Ticket中增加私有成员map<Proxy * , int> ,用来存储自己的多个代理,为version 2 的多代理版本。此处也不实现了。
version 4
使用引用计数
此方法也是version 2 的多代理版本,增加引用计数。计数归0时回收代理对象。
注:version 1 - 4都是我自己瞎想的....虽能实现,但是不知道是否实用。