【进阶Python】第八讲:代理模式

简介: 编程语言能够实现一项功能,而设计模式可以使得实现过程更加简洁、高效。设计模式不一定非要高大上,但是却可以使得代码更加易于阅读、扩展性更好、更加精妙合理。本文即单例模式之后讲解第二个设计模式--代理模式,同时会讲解它的应用场景及实现过程。

前言

学会使用一门编程语言来完成一项功能非常容易,尤其是Python、Go这些脚本语言,也许对于有一定编程基础的同学而言只需要一周或者一天时间。但是如果要想让写的代码变得更加简洁易读、执行效率更高、可扩展性更好,那么就需要超越编程语言之外的知识,这就是设计模式

在前面文章中,我介绍了一种比较常用的一种设计模式:单例模式。其实软件设计模式有非常多,代理模式、桥接模式、适配器、享元、工厂模式等。这些设计模式有的用的较多,有的在特定场景下才会用到,我会挑选个别应用场景较多的讲解一下。本文的要讲的就是代理模式,话不多说,下面开始代理模式的介绍及在Python中代理模式的实现方式。

代理模式

0.png

提到代理这个词汇,应该很多人都不陌生,甚至会有很多人用过。在编程语言之外,我们所接触的代理主要是在网络通信方面会涉及。当我们的网络不能直接与目标主机进行通信时,例如,我们不能直接访问Google、Facebook,我们可以通过搭建代理服务器的方式实现我们所用的网络与目标主机之间的通信,这就是网络中代理的概念。用一句话来概括就是:允许一个网络终端(一般为客户端)通过这个服务与另一个网络终端(一般为服务器)进行非直接的连接

之所以开始便讲解网络代理,是因为代理模式和网络代理有着很多相似的特点,而我们日常中接触更多的是网络代理,这样类比一下能够有助于大家的理解。

代理模式中,我们作为访问者就相当于编程语言中调用的实体,目标主机就相当于被调用的实体,它们二者直接不产生直接联系,而是通过中间的代理服务器(代理实体)来实现二者的间接联系。

代理模式的作用

一个概念的产生,自然有它的价值存在,代理模式也是这样,简而言之,概括代理模式的作用如下:

当我们访问一个实体考虑到安全等因素不方便时,代理可以为这个实体提供一个替代者,来控制它的访问权限和访问内容。

通俗的来讲,代理模式就如同一个"过滤器",它不实现具体功能,具体功能由被调用的实体来实现,代理实现的是对调用的控制功能,它能够允许或者拒绝调用实体对被调用实体的访问。

举个例子,我们访问一个具备敏感数据时,需要提供一个验证信息,比如,用户名、密码,代理模式完成的是更具访问者提供的用户名和密码来判断是否允许它进一步调用实体的功能。

代理模式的适用场景

一个设计模式,只有当它有了应用场景,它才具备存在的价值。代理模式有很多可以使用的场景,主要分为如下几类:

远程代理:为一个对象的地址空间提供局部代表。

虚拟代理:根据需要来创建开销较大的对象。

保护代理:用于对象应该具有不同访问权限的场景,控制对原始对象的访问。

智能指引:取代简单的指针,它在访问对象时执行一些附加操作。

-- 引自《设计模式:可复用面向对象软件的基础》

Python代理模式

1.png


代理模式在Java、C++中使用较多,可以用于虚拟代理和远程代理。由于Python这门语言相对简单,在企业中也常用于算法模块的验证,在一些大型系统很少会采用Python这门语言,因此,在软件设计模式方面考虑相对较少。但是,我认为,养成一个良好的软件设计思维,对日常开发和维护也具有非常多的好处,能够让开发效率更高,能够让代码可靠性更高,能够让后期维护成本更低。

在开发代码实现Python代理模式之前,我们首先来设定一个应用场景,这样才能够更加体现它的价值,同时让各位更加容易理解。

场景设定

假如,我们现在想了解一个班级的情况,主要包括两点:人数和学习成绩。

当我们想要了解这个班级的人数时,这个数据不敏感,不涉及隐私,因此可以直接访问。但是,当我们想查询特定某个学生成绩时,这样就涉及隐私信息,需要提供对应学生的姓名(user_name),访问的密码(password)。

需求分析

针对这个场景,我们可以先分析一下,访问者就如同上述图中的客户端(Client),获取班级人数、成绩这些实际的功能是由实体对象实现,也就是图中的RealSubject。Client与RealSubject之间不能直接通信,它们只能通过中间的代理(Proxy)进行通信。而Proxy主要的职责就相当于一个控制开关,如果Client要访问班级人数,Proxy会检查这项数据所需要的权限,然后发现班级人数是非敏感数据可以直接访问,那么它会调用实体对象中的方法,返回结果。如果Client要访问某个学生的成绩,Proxy会检查这项数据是敏感数据,需要提供用户名和密码,如果Client提供的正确,则允许访问,否则拒绝访问。

编程实践

第一步,我们自定义一个异常处理类,当我们要访问的用户不在班级成绩列表时,则抛出异常,

class NotFindError(Exception):
    def __init__(self, msg):
        self.msg = msg

第二步,实现实体类,实体类实现了具体的功能,针对这个场景就两个方法:获取班级人数、获取指定学生的成绩,

class RealSubject(object):
    def __init__(self):
        self.score = {
            "张三": 90,
            "李四": 59,
            "王二": 61
        }
    def num_students(self):
        num = len(self.score.keys())
        print("The number of students is {num}".format(num=num))
    def get_score(self, user_name):
        _score = self.score.get(user_name)
        print("The score of {user} is {score}".format(user=user_name,
                                                      score=_score))

第三步,实现代理(Proxy),它通过对应功能的访问权限来确定是接受这个访问,还是拒绝这个访问,

注意:在这个示例中,我把密码直接写在初始化方法中,实际的项目是不允许这样的,不能把密码写在代码中,另外也不能使用明文密码,需要使用加密工具对明文密码进行加密。

class Proxy(object):
    def __init__(self):
        self.default_passwd = "9l0skjlsa"
        self.real_subject = RealSubject()
    def num_students(self):
        self.real_subject.num_students()
    def get_score(self, user_name):
        print("You are visiting {} score ...".format(user_name))
        passwd = input("Please input password : ")
        if passwd == self.default_passwd:
            if user_name in self.real_subject.score.keys():
                return self.real_subject.get_score(user_name)
            else:
                raise NotFindError("The student you are visiting not found.")
        else:
            raise ValueError("The password you provided is wrong!")

然后就是实现Client来调用对应的功能,为了测试上述代理的功能,使用3个测试样例,

  1. 密码错误,用户名正确;
  2. 密码正确,用户名错误;
  3. 密码正确,用户名正确;

密码错误,用户名正确

def client():
    proxy = Proxy()
    proxy.get_score("张三")
client()
# shell
You are visiting 张三 score ...
Please input password : kdksla
# 输出
ValueError: The password you provided is wrong!

密码正确,用户名错误

def client():
    proxy = Proxy()
    proxy.get_score("李三")
client()
# shell
You are visiting 张三 score ...
Please input password : 9l0skjlsa
# 输出
NotFindError: The student you are visiting not found.

密码正确,用户名正确

def client():
    proxy = Proxy()
    proxy.get_score("李四")
client()
# shell
You are visiting 张三 score ...
Please input password : 9l0skjlsa
# 输出
The score of 李四 is 59

本讲完整代码如下,

class NotFindError(Exception):
    def __init__(self, msg):
        self.msg = msg
class RealSubject(object):
    def __init__(self):
        self.score = {
            "张三": 90,
            "李四": 59,
            "王二": 61
        }
    def num_students(self):
        num = len(self.score.keys())
        print("The number of students is {num}".format(num=num))
    def get_score(self, user_name):
        _score = self.score.get(user_name)
        print("The score of {user} is {score}".format(user=user_name,
                                                      score=_score))
class Proxy(object):
    def __init__(self):
        self.default_passwd = "9l0skjlsa"
        self.real_subject = RealSubject()
    def num_students(self):
        self.real_subject.num_students()
    def get_score(self, user_name):
        print("You are visiting {} score ...".format(user_name))
        passwd = input("Please input password : ")
        if passwd == self.default_passwd:
            if user_name in self.real_subject.score.keys():
                return self.real_subject.get_score(user_name)
            else:
                raise NotFindError("The student you are visiting not found.")
        else:
            raise ValueError("The password you provided is wrong!")
def client():
    proxy = Proxy()
    proxy.get_score("张三")
client()
相关文章
|
22天前
|
设计模式 开发者 Python
Python编程中的设计模式:工厂方法模式###
本文深入浅出地探讨了Python编程中的一种重要设计模式——工厂方法模式。通过具体案例和代码示例,我们将了解工厂方法模式的定义、应用场景、实现步骤以及其优势与潜在缺点。无论你是Python新手还是有经验的开发者,都能从本文中获得关于如何在实际项目中有效应用工厂方法模式的启发。 ###
|
27天前
|
数据可视化 算法 JavaScript
基于图论的时间序列数据平稳性与连通性分析:利用图形、数学和 Python 揭示时间序列数据中的隐藏模式
本文探讨了如何利用图论分析时间序列数据的平稳性和连通性。通过将时间序列数据转换为图结构,计算片段间的相似性,并构建连通图,可以揭示数据中的隐藏模式。文章介绍了平稳性的概念,提出了基于图的平稳性度量,并展示了图分区在可视化平稳性中的应用。此外,还模拟了不同平稳性和非平稳性程度的信号,分析了图度量的变化,为时间序列数据分析提供了新视角。
54 0
基于图论的时间序列数据平稳性与连通性分析:利用图形、数学和 Python 揭示时间序列数据中的隐藏模式
|
2月前
|
算法 数据挖掘 Python
Python中的拟合技术:揭示数据背后的模式
Python中的拟合技术:揭示数据背后的模式
40 0
Python中的拟合技术:揭示数据背后的模式
|
18天前
|
Python
探索Python中的异步编程模式
【10月更文挑战第29天】在编程世界中,时间就是效率。Python的异步编程模式,就像是给程序装上了翅膀,让任务并行处理不再是梦想。本文将带你了解如何在Python中实现异步编程,解锁高效代码的秘密。
25 0
|
2月前
|
IDE JavaScript Java
Processing介绍及几个python模式下的案例
该文章介绍了Processing这一开源编程语言和环境,主要用于视觉艺术和设计领域,并提供了Python模式下的编程案例。
46 5
|
2月前
|
设计模式 安全 API
探索Python中的异步编程模式
【9月更文挑战第19天】在本文中,我们将深入探讨Python的异步编程世界。通过理解其背后的原理和实践应用,你将学会如何编写更加高效、响应更快的程序。文章将引导你从基础概念出发,逐步过渡到高级用法,确保你能够自信地运用异步特性来优化你的代码。
|
1月前
|
设计模式 机器学习/深度学习 算法
现代 Python:编写高效代码的模式、功能和策略(第 1 部分)
现代 Python:编写高效代码的模式、功能和策略(第 1 部分)
28 0
|
2月前
|
Python Windows
Python交互模式
Python交互模式。
16 1
|
3月前
|
存储 中间件 PHP
Python编程入门:从零到一的代码实践深入理解 PHP 中的中间件模式
【8月更文挑战第28天】本文旨在通过浅显易懂的方式,向初学者介绍Python编程的基础知识,并结合具体代码示例,带领读者一步步实现从零基础到能够独立编写简单程序的转变。文章将围绕Python语言的核心概念进行讲解,并通过实例展示如何应用这些概念解决实际问题。无论你是编程新手还是希望扩展技能的专业人士,这篇文章都将为你打开编程世界的大门。 【8月更文挑战第28天】在PHP的世界中,设计模式是构建可维护和可扩展软件的重要工具。本文将通过浅显易懂的语言和生动的比喻,带领读者深入理解中间件模式如何在PHP应用中发挥魔力,实现请求处理的高效管理。我们将一步步揭开中间件的神秘面纱,从它的定义、工作原理到
|
4月前
|
数据采集 网络协议 数据挖掘
网络爬虫进阶之路:深入理解HTTP协议,用Python urllib解锁新技能
【7月更文挑战第30天】网络爬虫是数据分析和信息聚合的关键工具。深入理解HTTP协议及掌握Python的urllib库对于高效爬虫开发至关重要。HTTP协议采用请求/响应模型,具有无状态性、支持多种请求方法和内容协商等特点。
51 3
下一篇
无影云桌面