Python面经【9】- Python设计模式专题-下卷

2023-12-12 10:30

本文主要是介绍Python面经【9】- Python设计模式专题-下卷,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Python面经【9】- Python设计模式专题-下卷

  • 三、 工厂模式
    • 1. 简单工厂:【静态方法】
    • 2. 工厂方法
    • 3. 抽象工厂
    • 四、 建造者模式
      • 1. 不使用设计模式
      • 2. 使用设计模式

三、 工厂模式

工厂模式是最常用的设计模式之一,这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。在工厂模式中,我们创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象
概念:创建一个对象的接口,让其子类自己决定实例化哪一个工厂类。工厂模式让类的实例化推迟到子类中进行。
主要解决:主要解决接口选择的问题
何时使用:我们明确计划不同条件下创建不同实例时。

在工厂设计模式中,客户端可以请求一个对象,而无需知道这个对象来自哪里;也就是,使用哪个类来生成这个对象。工厂背后的思想是简化对象的创建。与客户端自己基于实例化直接创建对象相比,基于一个中心化函数来实现,更易于追踪创建了那些对象。
通过将创建对象的代码和使用对象的代码解耦,工厂能够降低应用维护的复杂度。
工厂方法创建对象时,我们并没有与某个特定类耦合/绑定一起,而只是通过调用某个函数来提供关于我们想要什么的部分信息。这意味着修改这个函数比较容易,不需要同时修改使用这个函数的代码。

工厂通常有三种形式:
(1) 简单工厂:简单工厂并不是一个真正的设计模式,更像是一种编程习惯,它通过一个单独的类来创建实例,这个类通常包含一个静态方法,根据对不同的输入参数返回不同的对象;
(2) 工厂方法:工厂方式模式通过定义一个用于创建对象的接口,让子类决定实例化哪个类。这种模式使一个类的实例化延迟到其子类。
(3) 抽象工厂:它是一组用于创建一系列相关事物对象的工厂方法。

1. 简单工厂:【静态方法】

统一使用一个类作为对外接口,根据参数的不同,去选择实例化不同的类。

1. """2. 两个产品(两种类型的书)3. """4. class TechnicalBooks(object):5.     """技术书籍"""7.     def publish(self):8.         return "Python-Book"9.  
10. class LiteraryBooks(object):
11.     """文学书籍"""
12.  
13.     def publish(self):
14.         return "Black Hole Book"
15.  
16. # 现在我们有两种类型的书,分别是TechnicalBooks和LiteraryBooks的书
17. # 按照我们平常的方法来实例化的话,此时创建对象时是会对客户端暴露真正创建的类
18. it_books = TechnicalBooks()
19. ly_books = LiteraryBooks()
20.  
21. # 这时我们就可以构造一个"简单工厂"把所有实例化的过程封装在里面,把真正实例的类隐藏起来
22. class SimpleFactory(object):
23.     """简单工厂"""
24.     @staticmethod
25.     def publish_book(name):
26.         if name == 'technical':
27.             return TechnicalBooks()
28.         elif name == 'literary':
29.             return LiteraryBooks()
30.  # 通过类调用:class_name.fun_name()
31. it_books2 = SimpleFactory.publish_book('technical')
32. ly_books2 = SimpleFactory.publish_book('literary')

简单工厂的好处在于,把不同的类实例化统一到一个“工厂”,即不对外暴露真正的创建类,也提供了一个对外的统一接口。但是简单模式有一个缺点,那就是违背了soild的“开闭原则”,加入我们还需要增加一种书籍,那就必须要对简单工厂SimpleFactory进行源码的修改。
简单工厂的使用场景:

  • 已经确定有多少具体的类,不会再增加的情况下使用。

2. 工厂方法

上面的简单工厂我们知道了,如果新增一些类型的时候会违背软件设计中的开闭原则,但是我们希望再扩展新类时,不要修改原来的代码,这个时候我们可以在简单工厂的基础上把SimpleFactory抽象成不同的工厂,每个工厂对应生成自己的产品,这就是工厂方法。

1. """2. 两个产品(两种类型的书)3. """4. from abc import ABC, abstractmethod5. # 真正进行实例化的类6. class TechnicalBooks(object):7.     """技术书籍"""8.     def publish(self):9.         return "Python-Book"
10.  
11. class LiteraryBooks(object):
12.     """文学书籍"""
13.     def publish(self):
14.         return "Black Hole Book"
15.  
16. # 抽象工厂:先定义抽象类,然后每种类型的书籍都有自己对于的工厂
17. class AbstractFactory(metaclass=abc.ABCMeta):
18.     """抽象工厂"""
19.     @abstractmethod
20.     def publish_book(self):
21.         pass
22.  
23. class TechnicalFactory(AbstractFactory):
24.     """技术书籍工厂"""
25. 
26.     def publish_book(self):
27.         return TechnicalBooks()
28.  
29. class LiteraryFactory(AbstractFactory):
30.     """文学书籍工厂"""
31.  
32.     def publish_book(self):
33.         return LiteraryBooks()
34.  
35. it_books2 = TechnicalFactory().publish_book()   
36. ly_books2 = LiteraryFactory().publish_book()    # 如果通过类调用是不带括号的# 该代码带括号等价于先创建实例然后通过实例调用方法

这样每个工厂就只负责生产自己的产品,避免了在新增产品时需要修改工厂的代码,遵循了“开闭原则”,如果需要新增产品时,只需要增加相应的工厂即可。
比如要增加一种小说类型的书籍,只需增加一个NovelBooks类和NovelFactory类。
工厂方法的使用场景:

  • 当系统中拥有的子类很多,并且以后可能还需要不断拓展增加不同的子类时。
  • 当设计系统时,还不明确具体有那些类时。

在工厂方法中,使用者不需要知道具体的产品类名,只需要知道其对应的工厂即可。

3. 抽象工厂

工厂方法解决了“开闭原则”的问题,但是我们出版书籍之前肯定还有其他的步骤,比如印刷。如果要每一个步骤我们就要写一个对应的工厂类,那我们就会需要创建很多多多的类了。为了解决这个问题,我们就需要抽象工厂类,让一个工厂可以生产同一类的多个产品或多个动作(步骤),这就是抽象工厂。

1. """2. 两个产品(两种类型的书)3. """4. import abc5.  6. # 印刷书籍7. class PrintingTechnicalBooks(object):8.     """印刷技术书籍"""9.     def printing(self):
10.         return "Print-Python-Book"
11.  
12. class PrintingLiteraryBooks(object):
13.     """印刷文学书籍"""
14.     def printing(self):
15.         return "Print Black Hole Book"
16.  
17. # 出版书籍
18. class TechnicalBooks(object):
19.     """出版技术书籍"""
20.     def publish(self):
21.         return "Python-Book"
22.  
23. class LiteraryBooks(object):
24.     """出版文学书籍"""
25.     def publish(self):
26.         return "Black Hole Book"
27.  
28. # 抽象工厂:先定义抽象类,然后每种类型的书籍都有自己对于的工厂
29. class AbstractFactory(metaclass=abc.ABCMeta):
30.     """抽象工厂"""
31.  
32.     @abc.abstractmethod
33.     def print_book(self):
34.         pass
35.  
36.     @abc.abstractmethod
37.     def publish_book(self):
38.         pass
39.  
40. class TechnicalFactory(AbstractFactory):
41.     """技术书籍工厂"""
42.  
43.     def print_book(self):
44.         return PrintingTechnicalBooks()
45.  
46.     def publish_book(self):
47.         return TechnicalBooks()
48.  
49. class LiteraryFactory(AbstractFactory):
50.     """文学书籍工厂"""
51.     def print_book(self):
52.         return PrintingLiteraryBooks()
53.  
54.     def publish_book(self):
55.         return LiteraryBooks()
56.  
58. # 实例化工厂对象
59. it = TechnicalFactory()
60. ly = LiteraryFactory()
61.  
62. # 印刷书籍
63. it_print = it.print_book()
64. ly_print = ly.print_book()
65. # 出版书籍
66. it_publish = it.publish_book()
67. ly_publish = ly.publish_book()
  • 抽象工厂模式与工厂方法模式的区别:
    • 抽象工厂中的一个工厂对象可以负责多个不同产品对象的创建。
  • 抽象工厂的使用场景:
    • 当多个产品(步骤)集合在一起,组成产品族时
    • 对应一个产品族时,如果只想显示接口而不是实现时。

四、 建造者模式

将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示,建造者模式将所有细节都交由子类实现。需求:画人物,要求画一个人的左手、右手、左脚、右脚和身体,画一个瘦子和一个胖子。

1. 不使用设计模式

1. if __name__=='__name__':2.     print '画左手'3.     print '画右手'4.     print '画左脚'5.     print '画右脚'6.     print '画胖身体'7.  8.     print '画左手'9.     print '画右手'
10.     print '画左脚'
11.     print '画右脚'
12.     print '画瘦身体'

这样写的缺点每画一个人,都要画他的5个部位,这些部位有一些是可以重用的,所以调用起来会比较繁琐,而且客户调用的时候可能会忘记画其中一个部分,所以容易出错。
建造一个抽象的类Builder,声明画他的五个部位的方法,每画一种人,就新建一个继承Builder的类,这样新建的类就必须实现Builder的所有方法,这里主要运用了抽象方法的特性,父类定义了几个抽象的方法,子类必须要实现这些方法,否则就报错,这里解决了会漏画一个部位的问题。建造一个指挥者类Director,输入一个Builder的方法,定义一个draw的方法,把画这五个部位的方法调用都放在里面,这样调用起来就不会繁琐了。

  • Python本身不提供抽象类和接口机制,要想实现抽象类,可以借助abc模块。Abc模块是Abstract Base Class的缩写。
  • 被@abstractmethod装饰为抽象方法后,该方法不能被实例化;除非子类实现了基类的抽象方法,所以能实例化。

2. 使用设计模式

1. #encodig=utf-82. from abc import ABCMeta, abstractmethod3. class Builder():4.     __metaclass__ = ABCMeta5.     6.     @abstractmethod7.     def draw_left_arm(self):8.         pass9.
10.     @abstractmethod
11.     def draw_right_arm(self):
12.         pass
13.     
14.     @abstractmethod
15.     def draw_left_foot(self):
16.         pass
17.     
18.     @abstractmethod
19.     def draw_right_foot(self):
20.         pass
21.     
22.     @abstractmethod
23.     def draw_body(self):
24.         pass
25.     
26. class Thin(Builder): # 继承抽象类,必须实现其中定义的方法
27.     def draw_left_arm(self):
28.         print('画瘦子左手')
29.     
30.     def draw_right_arm(self):
31.         print('画瘦子右手')
32.     
33.     def draw_left_foot(self):
34.         print('画瘦子左脚')
35.     
36.     def draw_right_foot(self):
37.         print('画瘦子右脚')
38.     
39.     def draw_body(self):
40.         print('画瘦子身体')
41.         
42. class Fat(Builder): # 继承抽象类,必须实现其中定义的方法
43.     def draw_left_arm(self):
44.         print('画胖子左手')
45.     
46.     def draw_right_arm(self):
47.         print('画胖子右手')
48.     
49.     def draw_left_foot(self):
50.         print('画胖子左脚')
51.     
52.     def draw_right_foot(self):
53.         print('画胖子右脚')
54.     
55.     def draw_body(self):
56.         print('画胖子的身体')
57.         
58. class Director():
59.     def __init__(self, person):
60.         self.person = person
61.         
62.     def draw(self):
63.         self.person.draw_left_arm()
64.         self.person.draw_right_arm()
65.         self.person.draw_left_foot()
66.         self.person.draw_left_foot()
67.         self.person.draw_body()
68.         
69. if __name__ == '__main__':
70.     thin = Thin()
71.     fat = Fat()
72.     director_thin = Director(thin)
73.     director_thin.draw()
74.     director_fat = Director(fat)
75.     director_fat.draw()

建造者模式用于将一个复杂的对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

这篇关于Python面经【9】- Python设计模式专题-下卷的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/484277

相关文章

Python按照24个实用大方向精选的上千种工具库汇总整理

《Python按照24个实用大方向精选的上千种工具库汇总整理》本文整理了Python生态中近千个库,涵盖数据处理、图像处理、网络开发、Web框架、人工智能、科学计算、GUI工具、测试框架、环境管理等多... 目录1、数据处理文本处理特殊文本处理html/XML 解析文件处理配置文件处理文档相关日志管理日期和

Python标准库datetime模块日期和时间数据类型解读

《Python标准库datetime模块日期和时间数据类型解读》文章介绍Python中datetime模块的date、time、datetime类,用于处理日期、时间及日期时间结合体,通过属性获取时间... 目录Datetime常用类日期date类型使用时间 time 类型使用日期和时间的结合体–日期时间(

使用Python开发一个Ditto剪贴板数据导出工具

《使用Python开发一个Ditto剪贴板数据导出工具》在日常工作中,我们经常需要处理大量的剪贴板数据,下面将介绍如何使用Python的wxPython库开发一个图形化工具,实现从Ditto数据库中读... 目录前言运行结果项目需求分析技术选型核心功能实现1. Ditto数据库结构分析2. 数据库自动定位3

Python yield与yield from的简单使用方式

《Pythonyield与yieldfrom的简单使用方式》生成器通过yield定义,可在处理I/O时暂停执行并返回部分结果,待其他任务完成后继续,yieldfrom用于将一个生成器的值传递给另一... 目录python yield与yield from的使用代码结构总结Python yield与yield

python使用Akshare与Streamlit实现股票估值分析教程(图文代码)

《python使用Akshare与Streamlit实现股票估值分析教程(图文代码)》入职测试中的一道题,要求:从Akshare下载某一个股票近十年的财务报表包括,资产负债表,利润表,现金流量表,保存... 目录一、前言二、核心知识点梳理1、Akshare数据获取2、Pandas数据处理3、Matplotl

Django开发时如何避免频繁发送短信验证码(python图文代码)

《Django开发时如何避免频繁发送短信验证码(python图文代码)》Django开发时,为防止频繁发送验证码,后端需用Redis限制请求频率,结合管道技术提升效率,通过生产者消费者模式解耦业务逻辑... 目录避免频繁发送 验证码1. www.chinasem.cn避免频繁发送 验证码逻辑分析2. 避免频繁

精选20个好玩又实用的的Python实战项目(有图文代码)

《精选20个好玩又实用的的Python实战项目(有图文代码)》文章介绍了20个实用Python项目,涵盖游戏开发、工具应用、图像处理、机器学习等,使用Tkinter、PIL、OpenCV、Kivy等库... 目录① 猜字游戏② 闹钟③ 骰子模拟器④ 二维码⑤ 语言检测⑥ 加密和解密⑦ URL缩短⑧ 音乐播放

python panda库从基础到高级操作分析

《pythonpanda库从基础到高级操作分析》本文介绍了Pandas库的核心功能,包括处理结构化数据的Series和DataFrame数据结构,数据读取、清洗、分组聚合、合并、时间序列分析及大数据... 目录1. Pandas 概述2. 基本操作:数据读取与查看3. 索引操作:精准定位数据4. Group

Python pandas库自学超详细教程

《Pythonpandas库自学超详细教程》文章介绍了Pandas库的基本功能、安装方法及核心操作,涵盖数据导入(CSV/Excel等)、数据结构(Series、DataFrame)、数据清洗、转换... 目录一、什么是Pandas库(1)、Pandas 应用(2)、Pandas 功能(3)、数据结构二、安

Python使用Tenacity一行代码实现自动重试详解

《Python使用Tenacity一行代码实现自动重试详解》tenacity是一个专为Python设计的通用重试库,它的核心理念就是用简单、清晰的方式,为任何可能失败的操作添加重试能力,下面我们就来看... 目录一切始于一个简单的 API 调用Tenacity 入门:一行代码实现优雅重试精细控制:让重试按我