浅谈Python设计模式 - 代理模式

声明:本系列文章主要参考《精通Python设计模式》一书,并且参考一些资料,结合自己的一些看法来总结而来。

一、在某些应用中,我们想要在访问某个对象之前执行一个或者多个重要的操作,例如,访问敏感信息 -- 在允许用户访问敏感信息之前,我们希望确保用户具备足够的去权限。同时在网络访问时,限制某些网络的访问等操作。

二、把一个计算成本较高的对象的创建过程延迟到用户首次真正使用它的时候才进行。

以上的情况就可以使用 代理设计模式 。

代理模式:因使用代理对象再访问实际对象之前执行重要操作而得其名。

示例:

之前想用《精通Python设计模式》中的示例来说明,但是发现很负责不太好理解,于是有了接下来的示例:阿里云:Python与设计模式 -代理模式。

一、首先构件一个网络服务器:

#该服务器接受如下格式数据,addr代表地址,content代表接收的信息内容
info_struct=dict()
info_struct["addr"]=10000
info_struct["content"]=""
class Server:
    content=""
    def recv(self,info):
        pass
    def send(self,info):
        pass
    def show(self):
        pass
class infoServer(Server):
    def recv(self,info):
        self.content=info
        return "recv OK!"
    def send(self,info):
        pass
    def show(self):
        print "SHOW:%s"%self.content

infoServer有接收和发送的功能,发送功能由于暂时用不到,保留。另外新加一个接口show,用来展示服务器接收的内容。接收的数据格式必须如info_struct所示,服务器仅接受info_struct的content字段。

二、若此时有需求,该网络服务器只允许部分网络IP进行访问,那么需要设置白名单,该怎么做呢?显然可以有如下两种方式:

①、修改Server结构是个方法,即在进入server时,做一系列逻辑判断。但这显然不符合软件设计原则中的单一职责原则。

②、使用代理,即利用代理来进行逻辑判定,若在白名单中,则允许访问,若不在则拒绝。

class serverProxy:
    pass
class infoServerProxy(serverProxy):
    server=""
    def __init__(self,server):
        self.server=server
    def recv(self,info):
        return self.server.recv(info)
    def show(self):
        self.server.show()

class whiteInfoServerProxy(infoServerProxy):
    white_list=[]
    def recv(self,info):
        try:
            assert type(info)==dict
        except:
            return "info structure is not correct"
        addr=info.get("addr",0)
        if not addr in self.white_list:
            return "Your address is not in the white list."
        else:
            content=info.get("content","")
            return self.server.recv(content)
    def addWhite(self,addr):
        self.white_list.append(addr)
    def rmvWhite(self,addr):
        self.white_list.remove(addr)
    def clearWhite(self):
        self.white_list=[]

代理中有一个server字段,控制代理的服务器对象,infoServerProxy充当Server的直接接口代理,而whiteInfoServerProxy直接继承了infoServerProxy对象,同时加入了white_list和对白名单的操作。这样,在场景中使用一个白名单服务器代理类来实现,在接收请求时,做验证:内容是否符合规则、访问者的IP地址是否在白名单中,若通过则接收内容。

那么有了白名单服务器代理,该怎么使用呢?

if  __name__=="__main__":
    info_struct = dict()
    info_struct["addr"] = 10010
    info_struct["content"] = "Hello World!"
    info_server = infoServer()
    info_server_proxy = whiteInfoServerProxy(info_server)
    print(info_server_proxy.recv(info_struct))
    info_server_proxy.show()
    info_server_proxy.addWhite(10010)
    print (info_server_proxy.recv(info_struct))
    info_server_proxy.show()

打印如下:

Your address is not in the white list.
SHOW:
recv OK!
SHOW:Hello World!

这边我也把书中的示例放置在此。

class LazyProperty(object):
    '''利用装饰器的特性作为代理,给_resource初始化值'''
    def __init__(self, method):
        self.method = method
        self.method_name = method.__name__
        print('func name is:{}'.format(self.method_name))

    def __get__(self, obj, cls):
        '''使用值来替代方法'''
        if not obj:
            return None
        value = self.method(obj)
        print('value {}'.format(value))
        setattr(obj, self.method_name, value)
        return value


class Test(object):
    def __init__(self):
        self.x = 'foo'
        self.y = 'bar'
        self._resource = None
    
    @LazyProperty   # resource = LazyProperty(resource)
    def resource(self):
        print('init self._resource which is:{}'.format(self._resource))
        self._resource = tuple(range(5))
        return self._resource
    
def main():
    t = Test()
    print(t.x)
    print(t.y)
    print(t._resource)
    print(t.resource)
    print(t.__dict__)
    print(t.resource)
    # print(t._resource)

if __name__ == '__main__':
    main()

该示例:使用的是装饰器来实现对 resource方法的惰性加载,而该装饰器是使用数据描述符来实现的,故需要对数据描述符有一定的了解。

over~~,参考:https://yq.aliyun.com/articles/70738?utm_content=m_15329,感谢。。。

你可能感兴趣的:(浅谈Python设计模式 - 代理模式)