• 设计模式学习——代理模式(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赋值,此时它非空,真实对象自然可以绕过代理,使用方法了。

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

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

    在上周的类图上做了修改,去掉了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都是我自己瞎想的....虽能实现,但是不知道是否实用。

  • 相关阅读:
    学习加密(四)spring boot 使用RSA+AES混合加密,前后端传递参数加解密
    vue实现rsa加密,数字签名,md5加密等
    Thymeleaf 基本用法总结
    空格去
    SpringBoot+Shiro学习(七):Filter过滤器管理
    vue-lazyload的使用
    vue中使用base64和md5
    vuex使用一
    webpack使用七
    webpack使用六
  • 原文地址:https://www.cnblogs.com/chinxi/p/7396109.html
Copyright © 2020-2023  润新知