设计模式学习——代理模式(Proxy Pattern)之 强制代理(强校验,防绕过)

上周温习了代理模式: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赋值,此时它非空,真实对象自然可以绕过代理,使用方法了。

用上周的例子,与网络上搜到的方式就是:

车站出了新政策,自己不卖车票,但是可以通过自己想买什么票,得知要去哪里买(代理)。

设计模式学习——代理模式(Proxy Pattern)之  强制代理(强校验,防绕过)

在上周的类图上做了修改,去掉了Tickets的派生类(简单点....),与Proxy中独有的方法。在此,不把get_proxy方法写进基类,由派生类决定自己是否需要代理。

代理实现,也先用判断_proxy是否为空。最后会有修改版本。

  ///
/// @file Selling_Tickets.h
/// @author marrs(chenchengxi993@gmail.com)
/// @date 2017-08-13 20:35:28
/// #ifndef __SELLING_TICKETS_H__
#define __SELLING_TICKETS_H__ #include <iostream> namespace marrs{ using std::cout;
using std::endl;
using std::string; class SellingTickets
{
public:
virtual ~SellingTickets(){} public:
virtual void Selling() = ;
virtual void Price() = ; }; } #endif // __SELLING_TICKETS_H__
  ///
/// @file Tickets.h
/// @author marrs(chenchengxi993@gmail.com)
/// @date 2017-08-13 20:39:17
/// #ifndef __TICKETS_H__
#define __TICKETS_H__ #include "Selling_Tickets.h" namespace marrs{
class Proxy;
class Tickets
: public SellingTickets
{
public:
Tickets(string ticket_type);
public:
void Selling();
void Price(); public:
Proxy * Get_Proxy(); private:
bool Is_Proxy(); private:
Proxy * _proxy;
string _ticket_type;
}; } #endif // __TICKETS_H__
  ///
/// @file Proxy.h
/// @author marrs(chenchengxi993@gmail.com)
/// @date 2017-08-13 20:46:13
/// #ifndef __PROXY_H__
#define __PROXY_H__ #include "Selling_Tickets.h" namespace marrs{
class Tickets;
class Proxy
: public SellingTickets
{
public:
Proxy(Tickets * ticket); public:
void Selling();
void Price(); private:
Tickets * _ticket; }; } #endif // __PROXY_H__
  ///
/// @file Tickets.cc
/// @author marrs(chenchengxi993@gmail.com)
/// @date 2017-08-19 14:38:00
/// #include "Tickets.h"
#include "Proxy.h" namespace marrs{ Tickets::Tickets(string ticket_type)
: _ticket_type(ticket_type)
{ } void Tickets::Selling()
{
if(Is_Proxy())
{
cout << "sell: " << _ticket_type << endl;
}
} void Tickets::Price()
{
if(Is_Proxy())
{
cout << "price: 100 RMB" << endl;
}
} Proxy * Tickets::Get_Proxy()
{
if(!_proxy)
{
_proxy = new Proxy(this);
}
return _proxy;
} bool Tickets::Is_Proxy()
{
if(!_proxy)
{
cout << "please use proxy" << endl;
return false;
}
return true;
} }
  ///
/// @file Proxy.cc
/// @author marrs(chenchengxi993@gmail.com)
/// @date 2017-08-19 14:52:18
/// #include "Proxy.h"
#include "Tickets.h" namespace marrs{ Proxy::Proxy(Tickets * ticket)
: _ticket(ticket)
{
} void Proxy::Selling()
{
_ticket->Selling();
} void Proxy::Price()
{
_ticket->Price();
} }

现在,先用前面搜到的例子进行测试:

  ///
/// @file Student.cc
/// @author marrs(chenchengxi993@gmail.com)
/// @date 2017-08-13 20:51:42
/// #include "Proxy.h"
#include "Tickets.h" using namespace marrs; int main()
{
Tickets * ticket = new Tickets("bus_ticket");
ticket->Price();
ticket->Selling(); Proxy * proxy = new Proxy(ticket);
proxy->Price();
proxy->Selling();
delete proxy; proxy = ticket->Get_Proxy();
proxy->Price();
proxy->Selling();
delete proxy; delete ticket; return ;
}

编译,运行:

[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: RMB
sell: bus_ticket

看着像是强制代理了。好,现在修改一下main:

  ///
/// @file Student.cc
/// @author marrs(chenchengxi993@gmail.com)
/// @date 2017-08-13 20:51:42
/// #include "Proxy.h"
#include "Tickets.h" using namespace marrs; int main()
{
Tickets * ticket = new Tickets("bus_ticket");
Proxy * proxy = ticket->Get_Proxy();
Proxy * proxy_other = new Proxy(ticket); proxy->Price();
proxy->Selling(); ticket->Price();
ticket->Selling(); proxy_other->Price();
proxy_other->Selling(); delete proxy;
delete ticket; return ;
}
[ccx@ubuntu ~/object-oriented/Proxy_Pattern_2]$>g++ * -o main.exe
[ccx@ubuntu ~/object-oriented/Proxy_Pattern_2]$>./main.exe
price: RMB
sell: bus_ticket
price: RMB
sell: bus_ticket
price: RMB
sell: bus_ticket

结果完全符合预期,真实对象也可以使用自己的方法了。甚至乱套了,随便来个代理都可以用了。

于是,我对其进行修改,对判断是不是proxy加了点东西:

version 1:

此方法设置了唯一代理

  ///
/// @file Tickets.h
/// @author marrs(chenchengxi993@gmail.com)
/// @date 2017-08-13 20:39:17
/// #ifndef __TICKETS_H__
#define __TICKETS_H__ #include "Selling_Tickets.h" namespace marrs{
class Proxy;
class Tickets
: public SellingTickets
{
public:
Tickets(string ticket_type);
~Tickets();
public:
void Selling(Proxy * proxy);
void Price(Proxy * proxy); private:
void Selling();
void Price(); public:
Proxy * Get_Proxy(); private:
bool Is_Proxy(Proxy * proxy) const; private:
string _ticket_type;
Proxy * _proxy;
}; } #endif // __TICKETS_H__
  ///
/// @file Proxy.h
/// @author marrs(chenchengxi993@gmail.com)
/// @date 2017-08-13 20:46:13
/// #ifndef __PROXY_H__
#define __PROXY_H__ #include "Selling_Tickets.h" namespace marrs{
class Tickets;
class Proxy
: public SellingTickets
{
public:
Proxy(Tickets * ticket); public:
void Selling();
void Price(); private:
Tickets * _ticket; }; } #endif // __PROXY_H__
  ///
/// @file Tickets.cc
/// @author marrs(chenchengxi993@gmail.com)
/// @date 2017-08-19 14:38:00
/// #include "Tickets.h"
#include "Proxy.h" namespace marrs{ Tickets::Tickets(string ticket_type)
: _ticket_type(ticket_type)
, _proxy(NULL)
{ } Tickets::~Tickets()
{
if(_proxy)
{
delete _proxy;
}
} void Tickets::Selling(Proxy * proxy)
{
if(Is_Proxy(proxy))
{
Selling();
}
} void Tickets::Price(Proxy * proxy)
{
if(Is_Proxy(proxy))
{
Price();
}
} void Tickets::Selling()
{
cout << "sell: " << _ticket_type << endl;
} void Tickets::Price()
{
cout << "price: 100 RMB" << endl;
} Proxy * Tickets::Get_Proxy()
{
if(!_proxy)
{
_proxy = new Proxy(this);
return _proxy;
}
return NULL;
} bool Tickets::Is_Proxy(Proxy * proxy) const
{
if(proxy != _proxy)
{
cout << "please use proxy" << endl;
return false;
}
return true;
} }
  ///
/// @file Proxy.cc
/// @author marrs(chenchengxi993@gmail.com)
/// @date 2017-08-19 14:52:18
/// #include "Proxy.h"
#include "Tickets.h" namespace marrs{ Proxy::Proxy(Tickets * ticket)
: _ticket(ticket)
{
} void Proxy::Selling()
{
_ticket->Selling(this);
} void Proxy::Price()
{
_ticket->Price(this);
} }
  ///
/// @file Student.cc
/// @author marrs(chenchengxi993@gmail.com)
/// @date 2017-08-13 20:51:42
/// #include "Proxy.h"
#include "Tickets.h" using namespace marrs; int main()
{
Tickets * ticket = new Tickets("bus_ticket");
Proxy * proxy = ticket->Get_Proxy(); proxy->Price();
proxy->Selling(); Proxy * proxy_other = new Proxy(ticket);
proxy_other->Price();
proxy_other->Selling(); ticket->Price(proxy);
ticket->Selling(proxy); ticket->Price(proxy_other);
ticket->Selling(proxy_other); delete proxy_other;
delete ticket; return ;
}
 [ccx@ubuntu ~/object-oriented/Proxy_Pattern_3]$>g++ *.h *.cc -o main.exe
[ccx@ubuntu ~/object-oriented/Proxy_Pattern_3]$>./main.exe
price: RMB
sell: bus_ticket
please use proxy
please use proxy
price: RMB
sell: bus_ticket
please use proxy
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都是我自己瞎想的....虽能实现,但是不知道是否实用。

上一篇:GlitchBot -HZNU寒假集训


下一篇:《Unix&Linux大学教程》学习笔记二:指令常识