【通俗说设计模式】七、代理模式 & Python示例 (结构型模式开篇)

专业介绍:

为其他对象提供一个代理以控制对这个对象的访问。这时,访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介。

通俗介绍: 

有些情况下,使用者(客户端)不能直接访问某个对象,可能是因为以下几点原因:

       1. 需要保护这个对象不被某些客户端/使用者更改。

       2. 想要扩展或剪去这个对象的某些功能,但不能/不便于直接修改此对象

       3. 直接访问对象的成本太高,需要中间对象代为访问,再提供给使用者

就提供一个中介(代理)给客户端使用,由中介直接访问对象并提供服务给客户端。

 举例:研发部要给数据开发部提供一个查询DB数据的接口,数据开发部只需要查询(select)的权限,其他权限都不需要,这个时候,研发部通常会写个基于http协议的接口给它,接口内做好权限的限制,那么这个接口就可以叫做一个数据库访问代理(中间件也可)。

代理模式的角色有3种:

  • 抽象主题
  • 真实主题
  • 代理

代理模式的缺点:

         1. 在访问者和被访问者中间增加了一层,降低了一定的访问速度

         2. 增加了系统复杂度。

下面的代码解决上面的例子(通过类的形式):

代码:

# 代理模式

import abc, six


# step-1: 定义抽象主题
@six.add_metaclass(abc.ABCMeta)
class AbstractDBAccessSubject:
    @abc.abstractmethod
    def select(self, sql): pass

    @abc.abstractmethod
    def delete(self, sql): pass

    @abc.abstractmethod
    def insert(self, sql): pass

    @abc.abstractmethod
    def update(self, sql): pass


# step-2: 定义具体主题
class DBAccesSubject(AbstractDBAccessSubject):
    def select(self, sql):
        return self.execute_sql(sql, 'select')

    def delete(self, sql):
        return self.execute_sql(sql, 'delete')

    def insert(self, sql):
        return self.execute_sql(sql, 'insert')

    def update(self, sql):
        return self.execute_sql(sql, 'update')

    def execute_sql(self, sql, op):
        return 'real_data', sql, op


# step-3: 定义代理(继承具体主题)
class DBAccesProxy(DBAccesSubject):
    def __init__(self, user, passwd):
        account_check = {
            'user1': {
                'passwd': 123, 'permission': ['select']
            }
        }
        self.user = ''
        self.permission = []
        self.logged = False
        u = account_check.get(user, {})
        if u.get('passwd') and u.get('passwd') == passwd:
            self.user = user
            self.permission = u.get('permission')
            self.logged = True
            return
        print('Invalid user and passwd!')

    def select(self, sql):
        if 'select' not in self.permission:
            print('Insufficient authority!')
            return
        return super(DBAccesProxy, self).select(sql)

    def delete(self, sql):
        if 'delete' not in self.permission:
            print('Insufficient authority!')
            return
        return super(DBAccesProxy, self).delete(sql)

    def insert(self, sql):
        if 'insert' not in self.permission:
            print('Insufficient authority!')
            return
        return super(DBAccesProxy, self).insert(sql)

    def update(self, sql):
        if 'update' not in self.permission:
            print('Insufficient authority!')
            return
        return super(DBAccesProxy, self).update(sql)


if __name__ == '__main__':
    db_access_proxy = DBAccesProxy('xxx', 123)  # Invalid user and passwd!
    # if not db_access_proxy.logged:
    #     exit()
    db_access_proxy = DBAccesProxy('user1', 123)
    s = db_access_proxy.select('select * from x')
    print(s)  # ('real_data', 'select * from x', 'select')
    db_access_proxy.update('update x set a=1')  # Insufficient authority!

说明:通过代码可以看出,代理类在提供DB访问的基础上,还提供了身份认证和权限控制功能,实现了一种无侵入的扩展。

根据代码还可以看出代理模式的两个缺点:

  1. 真实主题与代理主题一一对应,增加真实主题也要增加代理。
  2. 设计代理以前真实主题必须事先存在,不太灵活。(采用动态代理模式可以解决以上问题)

 

备注:关于abc, six库的基本用法参考文章 简单工厂模式 & Python示例 底部的介绍,: )

欢迎留言~

 

 

参考文章:

http://c.biancheng.net/view/1354.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值