Python Interview [9] - Python Design Pattern Special Topic - Volume 2

3. Factory model

Factory pattern is one of the most commonly used design patterns. This type of design pattern is a creational pattern, which provides the best way to create objects. In the factory pattern, when we create an object, we do not expose the creation logic to the client, and we use a common interface to point to the newly created object . Concept: Create an object interface and let its subclasses decide which factory class to instantiate. The factory pattern defers class instantiation to subclasses. Main solution: Mainly solve the problem of interface selectionWhen to use it: We Explicitly plan when creating different instances under different conditions.


In the factory design pattern, the client can request an object without knowing where the object came from; that is, which class was used to generate the object. The idea behind factories is to simplify object creation. Compared with the client itself creating objects directly based on instantiation, it is easier to track which objects are created based on a centralized function.
Factories can reduce the complexity of application maintenance by decoupling the code that creates objects from the code that uses them.
When the factory method creates an object, we are not coupled/bound to a specific class, but only provide partial information about what we want by calling a function. This means that it is easier to modify this function without also modifying the code that uses this function.

Factories usually come in three forms:
(1) Simple factory: Simple factory is not a real design pattern, but more like a programming habit that passes a separate class To create an instance, this class usually contains a static method that returns different objects according to different input parameters;
(2) Factory method: The factory mode pattern defines an interface for creating objects , let the subclass decide which class to instantiate. This pattern defers instantiation of a class to its subclasses.
(3) Abstract factory: It is a set of factory methods used to create a series of related objects.

1. Simple factory: [static method]

Use one class as the external interface, and choose to instantiate different classes based on different parameters.

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')

The advantage of a simple factory is that it unifies the instantiation of different classes into one "factory", that is, it does not expose the actual created class to the outside world, and it also provides a unified interface to the outside world. However, the simple mode has a disadvantage, that is, it violates the "opening and closing principle" of soil. If we add it, we need to add a book, and then the source code of the simple factory SimpleFactory must be modified.
Usage scenarios of simple factory:

  • It has been determined how many specific classes there are and will not be used in additional cases.

2. Factory method

We know the above simple factory. If we add some new types, it will violate the opening and closing principle in software design. However, we hope that when we expand new categories, we will not modify the original code. At this time, we can build on the simple factory. Abstract SimpleFactory into different factories, each factory generates its own products, this is the factory method.

1. """
 2. 两个产品(两种类型的书)
 3. """
 4. from abc import ABC, abstractmethod
 5. # 真正进行实例化的类
 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()    
	# 如果通过类调用是不带括号的
	# 该代码带括号等价于先创建实例然后通过实例调用方法

In this way, each factory is only responsible for producing its own products, which avoids the need to modify the factory code when adding new products. It follows the "opening and closing principle". If you need to add new products, you only need to add the corresponding Just the factory.
For example, if you want to add a novel type of book, you only need to add a NovelBooks class and a NovelFactory class.
Usage scenarios of factory methods:

  • When there are many subcategories in the system, and it may be necessary to continuously expand and add different subcategories in the future.
  • When designing the system, it is not clear exactly what classes there are.

In the factory method, the user does not need to know the specific product class name, only the corresponding factory.

3. Abstract factory

The factory method solves the problem of the "open and closed principle", but there must be other steps before we publish a book, such as printing. If we need to write a corresponding factory class for each step, then we will need to create many classes. In order to solve this problem, we need an abstract factory class so that a factory can produce multiple products or multiple actions (steps) of the same type. This It's an abstract factory.

1. """
 2. 两个产品(两种类型的书)
 3. """
 4. import abc
 5.  
 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()

  • The difference between abstract factory pattern and factory method pattern:
    • A factory object in an abstract factory can be responsible for the creation of multiple different product objects.
  • Usage scenarios of abstract factory:
    • When multiple products (steps) are brought together to form a product family
    • When corresponding to a product family, if you only want to display the interface instead of the implementation.

4. Builder Mode

Separates the construction of a complex object from its representation, so that the same construction process can create different representations,The builder pattern leaves all details to subclasses< /span>. Requirements: To draw characters, you are required to draw a person’s left hand, right hand, left foot, right foot and body, and draw a thin man and a fat man.

1. Not using design patterns

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 '画瘦身体'

The disadvantage of writing like this is that every time you draw a person, you have to draw 5 parts of him. Some of these parts can be reused, so it will be more cumbersome to call, and the customer may forget to draw one of them when calling. parts, so error-prone.
Create an abstract class Builder and declare the method of drawing its five parts. For each type of person drawn, create a new class that inherits Builder. In this way, the new class must implement all the features of Builder. Method, here mainly uses the characteristics of abstract methods. The parent class defines several abstract methods. The subclass must implement these methods, otherwise an error will be reported. Here we solve the problem of missing a part. The problem. Build a director class Director, enter a Builder method, define a draw method, and put all the method calls for drawing these five parts in it, so that calling them will not be cumbersome.

  • Python itself does not provide abstract classes and interface mechanisms. If you want to implement abstract classes, you can use the abc module. Abc module is the abbreviation of Abstract Base Class.
  • After being decorated as an abstract method by @abstractmethod, the method cannot be instantiated; unless the subclass implements the abstract method of the base class, it can be instantiated.

2. Use design patterns

1. #encodig=utf-8
 2. from abc import ABCMeta, abstractmethod
 3. class Builder():
 4.     __metaclass__ = ABCMeta
 5.     
 6.     @abstractmethod
 7.     def draw_left_arm(self):
 8.         pass
 9.
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()

The builder pattern is used to separate the construction of a complex object from its representation, so that the same construction process can create different representations.

Guess you like

Origin blog.csdn.net/s1_0_2_4/article/details/134888560