Skip to content

设计模式之代理模式

过去都是假的,回忆是一条没有归途的路,以往的一切春天是无法复原的。

Author: 李东阳

1、什么是代理模式

内容

为其他对象提供一种代理,来控制对这个对象的访问。

应用场景:

  • 远程代理:为远程的对象提供代理

  • 虚代理:根据需要创建很大的对象

  • 保护代理:控制对原始对象的访问,用于对象有不同的访问权限时

角色

  • 抽象实体(Subject)

  • 实体(Real Subject)

  • 代理(Proxy)

2、三种代理模式

2.1、远程代理

隐藏对象位于远程地址空间的事实 例如写入数据,而数据库不在本地,需要远程访问。隐藏数据库不在本地的事实,使用代理进行远程存储。

2.2、虚代理

为了节省资源开销,在功能没有被真正调用时,就不运行。 例如浏览器中的无图模式,不显示图片,等你真正需要查看某张时,点击才会真正加载图像,不点击时,只会告诉你,此处是一张图像,并不显示

2.3、保护代理

为了区分用户权限而设置的代理。 例如普通用户只有访问权限,而开发人员有写入权限。

3、代码实现

远程代理不做过多解释,这里主要介绍虚代理和保护代理。

3.1、虚代理的实现

举个例子:

大多数项目中都会用到文件读取这个功能,我们就拿它举例子好了,

每个人应该都玩游戏,但是你们有没有发现一个现象。就是越炫酷或者大型的游戏,它的启动加载就会越慢。之所以启动得慢,大家应该知道其实是它在加载一些游戏所需要的资源文件等等。其实这里就用到了虚代理,它这些资源肯定不是一次性加载完成的,如果是那你可以等上几个小时了。游戏启动时只加载它的一些启动界面等一些资源,后面的皮肤啊,什么的,肯定是用户什么时候需要在什么时候加载。

文件读写实现:

from abc import ABCMeta, abstractmethod


class Subject(metaclass=ABCMeta):
    @abstractmethod
    def get_content(self):  # 读取文件内容方法
        pass

    @abstractmethod
    def set_content(self, content):  # 修改文件内容方法
        pass


class RealSubject(Subject):
    def __init__(self, filename):
        self.filename = filename
        print('读取文件内容!')
        with open(self.filename, 'r', encoding='utf-8') as f:
            self.content = f.read()  # 可以看得到,这里一初始化就读取文件内容到内存中了,如果后面用户没有读取或者修改,那不白白浪费内存吗?

    def get_content(self):
        return self.content

    def set_content(self, content):
        with open(self.filename, 'w', encoding='utf-8') as f:
            f.write(content)


subj = RealSubject('test.txt')
"""
读取文件内容!
"""

这种一上来就加载不必要的资源到内存中的方法是不可取得,大家尽量避免。

虚代理实现文件读取:

from abc import ABCMeta, abstractmethod


# 抽象实体
class Subject(metaclass=ABCMeta):
    @abstractmethod
    def get_content(self):
        pass

    @abstractmethod
    def set_content(self, content):
        pass


# 实体
class RealSubject(Subject):
    def __init__(self, filename):
        self.filename = filename
        print('读取文件内容!')
        with open(self.filename, 'r', encoding='utf-8') as f:
            self.content = f.read()

    def get_content(self):
        return self.content

    def set_content(self, content):
        with open(self.filename, 'w', encoding='utf-8') as f:
            f.write(content)


# 虚代理
class VirtualProxy(Subject):
    def __init__(self, filename):
        self.filename = filename
        self.subj = None

    def get_content(self):
        if not self.subj:
            self.subj = RealSubject(self.filename)  # 返回实体对象
        return self.subj.get_content()

    def set_content(self, content):
        if not self.subj:
            self.subj = RealSubject(self.filename)

        return self.subj.set_content(content)


subj = VirtualProxy('test.txt')
print(subj.get_content())  # 当我们调用读取文件内容函数时才会将文件读取到内存

3.2、保护代理的实现

这里代理就让用户只有读文件的权限,不能写

代码实现:

from abc import ABCMeta, abstractmethod

# 抽象实体
class Subject(metaclass=ABCMeta):
    @abstractmethod
    def get_content(self):
        pass

    @abstractmethod
    def set_content(self, content):
        pass


# 实体
class RealSubject(Subject):
    def __init__(self, filename):
        self.filename = filename
        print('读取文件内容!')
        with open(self.filename, 'r', encoding='utf-8') as f:
            self.content = f.read()

    def get_content(self):
        return self.content

    def set_content(self, content):
        with open(self.filename, 'w', encoding='utf-8') as f:
            f.write(content)


# 保护代理
class ProtectedSubject(Subject):
    def __init__(self, filename):
        self.subj = RealSubject(filename)

    def get_content(self):
        return self.subj.get_content()

    def set_content(self, content):
        raise PermissionError('无写入权限!')


subj = ProtectedSubject('test.txt')
print(subj.get_content())
subj.set_content('abc')