本文主要是介绍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设计模式专题-下卷的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!