《Python编程实战:运用设计模式、并发和程序库创建高质量程序》—— 2.5 外观模式

简介:

本节书摘来自华章出版社《Python编程实战:运用设计模式、并发和程序库创建高质量程序》一 书中的第2章,第2.5节,作者:(美) Mark Summerfield,更多章节内容可以访问云栖社区“华章计算机”公众号查看。

2.5 外观模式

如果某套接口因为太过复杂或太专注于底层细节而变得不易使用,那么可考虑用“外观模式”(Fa?ade Pattern)将其简化并统合起来。
由Python标准库所提供的模块可以处理gzip、tarball、zip等格式的压缩文档,不过处理每种格式所用的接口却不相同。现在假定我们想通过一套简单而一致的接口来获知压缩文档里的各个文件名,并将其解压缩。本节将使用外观模式来设计这套接口,把真正的处理工作交给标准库来做。

63b9aef33973767ce13d95ae6ed2583dedf04bec

图2.7演示了我们想要提供给用户的接口(其中含有filename属性、names()方法与unpack()方法)以及该接口下掩藏的三套底层接口。Archive实例中存有压缩文档的名称,只有当用户询问其中压缩的文件名或要求对其解压缩时,才需要真正把压缩文档打开。(本节中的范例代码选自Unpack.py文件。)
screenshot

self._names变量用来保存一个callable,这个callable可以返回压缩文档内的文件名列表。self._unpack变量与之相似,其所存放的callable对象可把压缩文档中的所有文件都解压到当前目录。self._file存放打开的文件对象,此对象用来表示当前这份压缩文档。self.filename是个只读属性,用来保存压缩文档本身的文件名。
screenshot

如果用户打开了压缩文档之后又想修改filename属性(比如通过archive.filename = newname语句来修改),那么Archive会先把当前这份压缩文档关掉。由于Archive类采用了“延迟求值”(lazy evaluation)机制,所以修改属性之后,新的压缩文档并不会立即开启,只在有需要时才会打开它。
screenshot

按理说,用户在用完Archive类的实例之后,应该调用其close()方法。该方法会把已经打开的文件对象关掉,并把self._name、self._unpack和self._file设为None,令这些变量失效。
但实际上,用户只要在with语句范围内使用,就无须自行调用close(),因为我们已经把Archive类做成了“情境管理器”(context manager)。比方说,可以这样来使用它:
screenshot

上述代码创建了Archive实例,用来把zip格式压缩文档中的文件名打印到控制台上,并把其中所有文件都解压至当前目录。由于archive是个环境管理器,所以当程序执行到with语句块的范围之外时,会自动执行archive.close()。
screenshot

只要有上面这两个方法,Archive就能成为环境管理器。__enter__()方法返回self(也就是当前这个Archive实例),此返回值会赋给with ... as语句中的变量。__exit__()方法会把当前已经打开的文件对象关掉,由于此方法默认返回None,所以执行过程中发生的异常会照常传播。
screenshot

上述方法会返回压缩文档中的文件名列表,若该文档尚未开启,则调用self._prepare()方法将压缩文件打开,并把适当的callable赋给self._names与self._unpack。
screenshot

上述方法会把压缩文档中的所有文件都解压,不过我们稍后就会看到,只有在每个文件的名称都“安全”(safe)时,才会这么做。
screenshot

上述方法会把解压前的准备工作指派给合适的方法。由于tarball与zip格式所需的代码非常相似,所以我们把这两种压缩文档交由同一个方法处理。gzip格式的压缩文档与二者不同,因此单独放在另一个方法中处理。
这两个“准备方法”(preparation method)都必须把对应的callable赋给self.names及self._unpack变量,使刚才的names()与unpack()方法可以调用这些callable。
screenshot

上述方法首先创建名为safe_extractall()的嵌套函数,该函数检查压缩文档中的文件名是否均安全,如果is_safe()方法判定某些文件名不安全,那么safe_extractall()方法就会抛出ValueError。若是所有文件名都没问题,那么就调用tarball.TarFile.extractall()或zipfile.ZipFile.extractall()方法。
创建好safe_extractall()函数后,我们根据压缩文档的扩展名来创建tarfile.Tarfile或zipfile.ZipFile,并将其赋给self._file。接下来,把self._names的值设置成相应的绑定方法(也就是namelist()或getnames()),并把self._unpack的值设为刚刚创建好的safe_extractall()函数。由于该函数是闭包,所以能够捕获self,继而可通过self来访问self._file的值,并调用相应的extractall()方法。(绑定方法与非绑定方法的区别请参阅本节中的补充知识。)

            绑定方法与非绑定方法

绑定方法(bound method)就是已经同类实例相关联的方法。假设现在有Form类,类中有个update_ui()方法。如果在Form的某个方法里写上bound = self.update_ui这行代码,那就等于把指向Form.update_ui()方法的对象引用赋给了bound,并把Form.update_ui()方法同Form类的特定实例(用self表示)相绑定。绑定方法可以直接调用,比如:bound()。
非绑定方法(unbound method)是不与实例相关联的方法。比方说,假如刚才那行代码写的是unbound = Form.update_ui,那么unbound还是会成为指向Form.update_ui()方法的对象引用,但这次不会与特定的实例相绑定。也就是说,如果想调用非绑定方法,那么必须把适当的实例用作其首个参数才行,例如:form = Form(); unbound(form)。(与传统的Python不同,Python 3严格来说没有“非绑定方法”这一概念,所以bound就是个底层函数对象,这两种对非绑定方法的处理方式只有在元编程时才会偶尔体现出差别。)
screenshot

如果将恶意压缩文档解压缩,那么可能会把重要的系统文件覆写成无用或危险的内容。因此,切勿把包含绝对路径或相对路径的压缩文档打开,而且总应该以“非特权用户”(unprivileged user)的身份开启压缩文档(也就是不要以“根用户”(root)或“管理员”(Administrator)身份开启)。
如果文件名以“斜线”(forward slash)或“反斜线”(backslash)开头(这表示绝对路径),包含“../”、“..”(由于相对路径的目标不定,所以含有这两种文件名的压缩文档也不安全)或以“D:”这样的Windows盘符开头,那么is_safe()方法就返回False。
换句话说,以绝对路径开头或其中包含相对路径的文件名都是不安全的,而其他文件名则会使该方法返回True。
screenshot

上述方法将打开的文件对象赋给self._file变量,并把适当的callable赋给self._names及self._unpack变量。这次我们需要自己编写extractall()函数来读写相关数据。
外观模式很适合用来创建简单易用的接口,其优点在于能够隔离底层细节,而缺点则是可能会丧失某些微调能力。然而外观模式并不会把底层功能遮掩或废弃,所以大部分时间里都可以直接使用外观模式,而在需要微调时,则可以深入底层的类。
外观模式看起来很像适配器模式,其区别在于,外观模式是在复杂的接口上提炼出一套简单的接口,而适配器则是把其他接口(未必很复杂)转换成标准接口。这两种模式可以结合起来。比方说,我们可以定义一套处理压缩文档的标准接口(能够处理tarball、zip及Windows系统的.cab等格式),并用适配器模式把每种格式的压缩文档处理接口都分别转换成标准接口,然后在标准接口上面搭建外观层,这样用户就无须关注当前操作的压缩文档是哪种格式了。

相关文章
|
2月前
|
调度 Python
探索Python高级并发与网络编程技术。
可以看出,Python的高级并发和网络编程极具挑战,却也饱含乐趣。探索这些技术,你将会发现:它们好比是Python世界的海洋,有穿越风暴的波涛,也有寂静深海的奇妙。开始旅途,探索无尽可能吧!
68 15
|
2月前
|
设计模式 Java 数据库连接
【设计模式】【结构型模式】外观模式(Facde)
一、入门 什么是外观模式? 一种结构型设计模式,通过为子系统中的一组接口提供一个统一的高层接口(称为外观),来简化客户端与复杂子系统的交互过程。其本质是建立抽象层来隔离复杂度。 为什么要有外观模式?
89 9
|
6月前
|
设计模式 缓存 应用服务中间件
「全网最细 + 实战源码案例」设计模式——外观模式
外观模式(Facade Pattern)是一种结构型设计模式,旨在为复杂的子系统提供一个统一且简化的接口。通过封装多个子系统的复杂性,外观模式使外部调用更加简单、易用。例如,在智能家居系统中,外观类可以同时控制空调、灯光和电视的开关,而用户只需发出一个指令即可。
184 69
|
4月前
|
设计模式 机器学习/深度学习 前端开发
Python 高级编程与实战:深入理解设计模式与软件架构
本文深入探讨了Python中的设计模式与软件架构,涵盖单例、工厂、观察者模式及MVC、微服务架构,并通过实战项目如插件系统和Web应用帮助读者掌握这些技术。文章提供了代码示例,便于理解和实践。最后推荐了进一步学习的资源,助力提升Python编程技能。
|
9月前
|
监控 并行计算 数据处理
构建高效Python应用:并发与异步编程的实战秘籍,IO与CPU密集型任务一网打尽!
在Python编程的征途中,面对日益增长的性能需求,如何构建高效的应用成为了每位开发者必须面对的课题。并发与异步编程作为提升程序性能的两大法宝,在处理IO密集型与CPU密集型任务时展现出了巨大的潜力。今天,我们将深入探讨这些技术的最佳实践,助你打造高效Python应用。
132 0
|
8月前
|
设计模式 开发者 Python
Python编程中的设计模式:工厂方法模式###
本文深入浅出地探讨了Python编程中的一种重要设计模式——工厂方法模式。通过具体案例和代码示例,我们将了解工厂方法模式的定义、应用场景、实现步骤以及其优势与潜在缺点。无论你是Python新手还是有经验的开发者,都能从本文中获得关于如何在实际项目中有效应用工厂方法模式的启发。 ###
|
8月前
|
设计模式 开发者 Python
Python编程中的设计模式应用与实践感悟####
本文作为一篇技术性文章,旨在深入探讨Python编程中设计模式的应用价值与实践心得。在快速迭代的软件开发领域,设计模式如同导航灯塔,指引开发者构建高效、可维护的软件架构。本文将通过具体案例,展现设计模式如何在实际项目中解决复杂问题,提升代码质量,并分享个人在实践过程中的体会与感悟。 ####
|
8月前
|
设计模式 算法 搜索推荐
Python编程中的设计模式:优雅解决复杂问题的钥匙####
本文将探讨Python编程中几种核心设计模式的应用实例与优势,不涉及具体代码示例,而是聚焦于每种模式背后的设计理念、适用场景及其如何促进代码的可维护性和扩展性。通过理解这些设计模式,开发者可以更加高效地构建软件系统,实现代码复用,提升项目质量。 ####
|
8月前
|
设计模式 监控 算法
Python编程中的设计模式应用与实践感悟###
在Python这片广阔的编程疆域中,设计模式如同导航的灯塔,指引着开发者穿越复杂性的迷雾,构建出既高效又易于维护的代码结构。本文基于个人实践经验,深入探讨了几种核心设计模式在Python项目中的应用策略与实现细节,旨在为读者揭示这些模式背后的思想如何转化为提升软件质量的实际力量。通过具体案例分析,展现了设计模式在解决实际问题中的独特魅力,鼓励开发者在日常编码中积极采纳并灵活运用这些宝贵的经验总结。 ###
|
8月前
|
API 数据处理 Python
探秘Python并发新世界:asyncio库,让你的代码并发更优雅!
在Python编程中,随着网络应用和数据处理需求的增长,并发编程变得愈发重要。asyncio库作为Python 3.4及以上版本的标准库,以其简洁的API和强大的异步编程能力,成为提升性能和优化资源利用的关键工具。本文介绍了asyncio的基本概念、异步函数的定义与使用、并发控制和资源管理等核心功能,通过具体示例展示了如何高效地编写并发代码。
179 2

热门文章

最新文章

推荐镜像

更多