Skip to content

Commit 57cdcb3

Browse files
committed
更新第二章部分段落
1 parent 9a7bcdd commit 57cdcb3

File tree

2 files changed

+20
-20
lines changed

2 files changed

+20
-20
lines changed

第二章-构造器模式.md

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,21 @@
33

44
Imagine that we want to create an object that is composed of multiple parts and the composition needs to be done step by step. The object is not complete unless all its parts are fully created. That's where the Builder design pattern can help us. The Builder pattern separates the construction of a complex object from its representation. By keeping the construction separate from the representation, the same construction can be used to create several different representations [GOF95, page 110], [j.mp/builderpat].
55

6-
想象一下,我们要一个由多个部分合成的对象,而且合成需要一步步的来操作。这个对象在其自身所有部分都完全创建之前是不完整的。这就是构造器模式能够帮助我们的地方。构造器模式通过自己的表现将一个复杂对象的构造进行分离。通过使用表现的构造分离,相同的构造介意被用到多个不同到表现上。
6+
想象一下,我们想要一个由多个部分合成的对象,而且合成需要一步步的来操作。这个对象在其自身所有部分都完全创建之前是不完整的。这就是构造器模式能够帮助我们的地方。构造器模式通过自己的表现将一个复杂对象的构造进行分离。通过使用表现的构造分离,相同的构造介意被用到多个不同到表现上。
77

88
A practical example can help us understand what the purpose of the Builder pattern is. Suppose that we want to create an HTML page generator, the basic structure (construction part) of an HTML page is always the same: it begins with <html> and finishes with </html>; inside the HTML section are the <head> and </head> elements, inside the head section are the <title> and </title> elements, and so forth. But the representation of the page can differ. Each page has its own title, its own headings, and different <body> contents. Moreover, the page is usually built in steps: one function adds the title, another adds the main heading, another the footer, and so on. Only after the whole structure of a page is complete can it be shown to the client using a final render function. We can take it even further and extend the HTML generator so that it can generate totally different HTML pages. One page might contain tables, another page might contain image galleries, yet another page contains the contact form, and so on.
99

10-
实际的例子可以帮助我们理解什么是使用构造器的目的。假设我们想要创建一个HTML页面生成器,基本的HTML页面结构总是相同的:以<html>开始并以</html>结束;HTML区域的内部是<head>和</head>元素,
10+
实际的例子可以帮助我们理解使用构造器的目的是什么。假设我们想要创建一个HTML页面生成器,基本的HTML页面结构都是相同的:以<html>开始并以</html>结束;内部HTML区域是<head>和</head>元素,内部头区域是<title>和</title>元素,等等。但是页面的表现又是不同的。每个页面都拥有自己的标题,自己的头,以及不同的<body>内容。此外,页面通常的组成有多个步骤:一个函数添加标题,另一个添加主要头部,另外一个添加footer,等等。仅在整个页面合成完毕后,才使用最后的渲染函数将页面显示给用户。我们可以做到跟进一步,去扩展HTML生成器,这样它就可以生成完全不同的HTML页面了。一个页面或许包含表格、一个页面可能含有图片展示,另外一个页面还可能包含联系人表单,等等。
1111

1212
The HTML page generation problem can be solved using the Builder pattern. In this pattern, there are two main participants: the builder and the director. The builder
1313
is responsible for creating the various parts of the complex object. In the HTML example, these parts are the title, heading, body, and the footer of the page. The director controls the building process using a builder instance. The HTML example means for calling the builder's functions for setting the title, the heading, and so on. Using a different builder instance allows us to create a different HTML page without touching any code of the director.
1414

15-
HTML页面生成器的问题可以使用构造器模式来解决。在这个模式中有两个主要的参与元素:构造器和经手人。构造器负责创建负责对象的多个部分。在HTML示例中,这些部分为主题,头部,主体,以及页面脚注。经手人使用构造器实例控制构建过程。HTML例子
15+
HTML页面生成器的问题可以使用构造器模式来解决。在这个模式中有两个主要的参与元素:构造器和经手人。构造器负责创建负责对象的多个部分。在HTML示例中,这些部分为主题,头部,主体,以及页面脚注。经手人使用构造器实例控制构建过程。HTML的例子中的部分为,标题,头部,主体,以及页面注脚。管理者使用一个构造器实例来控制构建过程。HTML的例子意味着要调用构造器的函数来设置标题,头部,等等。使用不同的构造器实例可以让我们不接触任何管理器的代码便可以创建不同的HTML页面。
1616

1717
## 真实的例子
1818
The Builder design pattern is used in fast-food restaurants. The same procedure is always used to prepare a burger and the packaging (box and paper bag), even if there are many different kinds of burgers (classic, cheeseburger, and more) and different packages (small-sized box, medium-sized box, and so forth). The difference between a classic burger and a cheeseburger is in the representation, and not in the construction procedure. The director is the cashier who gives instructions about what needs to be prepared to the crew, and the builder is the person from the crew that takes care of the specific order. The following figure provided by *www. sourcemaking.com* shows a **Unified Modeling Language (UML)** sequence diagram of the communication that takes place between the customer (client), the cashier (director), and the crew (builder) when a kid's menu is ordered [j.mp/builderpat].
1919

20-
构造器模式被用在了快餐店。相同的步骤一直用在了准备汉堡和打包上,即使存在不同类型的汉堡(原味,起司,等等)以及不同的包装(小号的盒子,中号的盒子,等等)原味汉堡和起司汉堡之间不同在于表现上,而不是在构造过程上。
20+
构造器模式被用在了快餐店上。相同的步骤一直用在了准备汉堡和打包上(盒子、纸袋),即使存在不同类型的汉堡(原味,起司,等等)以及不同的包装(小号的盒子,中号的盒子,等等)原味汉堡和起司汉堡之间不同在于外观,而不是制造过程上。管理器是给全体工作人员发出需要准备什么食材的收银员,构造器是员工之中负责特殊订单的人。下面是由*www. sourcemaking.com*提供的**Unified Modeling Language (UML)**图片,它展示了当产生一份儿童餐订单时,一张放置于消费者(用户),收银员(管理器),和员工(构造器)之间的沟通顺序图解。
2121

2222
![img](images/chapter2_1.png)
2323

@@ -28,17 +28,16 @@ The HTML example that was mentioned at the beginning of the chapter is actually
2828

2929
The **django-query-builder** library is another third-party Django library that relies on the Builder pattern. The django-query-builder library can be used for building SQL queries dynamically. Using this, we can control all aspects of a query and create a different range of queries, from simple to very complex [j.mp/djangowidgy].
3030

31-
django-query-builder库是另外一个第三方的Django库,它依赖于构造器模式。
31+
django-query-builder库是另外一个第三方的Django库,它依赖于构造器模式。django-query-builder库用来构建动态SQL查询。使用这个库,我们可以控制查询和创建一组不同查询的方方面面,从简单的到复杂都可以。
3232

3333
## 使用案例
3434
We use the Builder pattern when we know that an object must be created in multiple steps, and different representations of the same construction are required. These requirements exist in many applications such as page generators (like the HTML page generator mentioned in this chapter), document converters [GOF95, page 110], and User Interface (UI) form creators [j.mp/pipbuild].
3535

3636
在我们知道对象必须用到多个步骤才能创建,以及需要相同构造的不同表现时才会使用构造器模式。这些需求存在于很多的应用中,比如页面生成器(类似于本章提到的页面生成器),文档转换器,以及用户界面(UI)的表单创建器。
3737

38-
Some resources mention that the Builder pattern can also be used as a solution to the telescopic constructor problem [j.mp/wikibuilder]. The telescopic constructor problem occurs when we are forced to create a new constructor for supporting different ways of creating an object. The problem is that we end up with many constructors and long parameter lists, which are hard to manage. An example of the telescopic constructor is listed at the stackoverflow website [j.mp/sobuilder]. Fortunately, this problem does not exist in Python, because it can be solved in
39-
at least two ways:
38+
Some resources mention that the Builder pattern can also be used as a solution to the telescopic constructor problem [j.mp/wikibuilder]. The telescopic constructor problem occurs when we are forced to create a new constructor for supporting different ways of creating an object. The problem is that we end up with many constructors and long parameter lists, which are hard to manage. An example of the telescopic constructor is listed at the stackoverflow website [j.mp/sobuilder]. Fortunately, this problem does not exist in Python, because it can be solved in at least two ways:
4039

41-
有些资料提到构造器模式也可以作为伸缩构造器问题的一个解决方案。当我们被迫创建一个新的构造器以支持一个对象的不同创建方式,便会出现伸缩构造器问题。其问题在于,我们要
40+
有些资料提到构造器模式也可以作为伸缩构造器问题的一个解决方案。当我们被迫创建一个新的构造器以支持一个对象的不同创建方式,便会出现伸缩构造器问题。其问题在于,在终结时我们还有很多的构造器和长参数列表,这将难以管理。伸缩构造器的例子被列在了stackoveflow网站。幸运的是,在Python这个问题并不存在,因为它是至少可以使用两种方法来解决:
4241

4342
- With named parameters [j.mp/sobuipython]
4443
- With argument list unpacking [j.mp/arglistpy]
@@ -57,7 +56,7 @@ to return the final object when it needs it [GOF95, page 113], [j.mp/builderpat]
5756

5857
The new computer analogy might help to distinguish between a Builder pattern and a Factory pattern. Assume that you want to buy a new computer. If you decide to buy a specific preconfigured computer model, for example, the latest Apple 1.4 GHz Mac mini, you use the Factory pattern. All the hardware specifications are already predefined by the manufacturer, who knows what to do without consulting you. The manufacturer typically receives just a single instruction. Code-wise, this would look like the following (*apple-factory.py*):
5958

60-
新计算机的分析有助于区别构造器模式和工厂模式。假设你需要买一台新电脑。如果你决定买预先配置好的电脑,例如最新的Apple 1.4Ghz Mac mini,你使用的是工厂模式。所有硬件规格都已经由厂商预定义了,
59+
新计算机的分析有助于区别构造器模式和工厂模式。假设你需要买一台新电脑。如果你决定买预先配置好的电脑,例如最新的Apple 1.4Ghz Mac mini,你使用的是工厂模式。所有硬件规格都已经由厂商预定义了,厂家不用问你也知道该干什么。厂商通畅只会收到一条指令。代码使人明了,其内容如下(*apple-factory.py*):
6160

6261
```python
6362
MINI14 = '1.4GHz Mac mini'
@@ -134,8 +133,8 @@ class HardwareEngineer:
134133
self.builder.configure_gpu(gpu))]
135134

136135
@property
137-
def computer(self):
138-
return self.builder.computer
136+
def computer(self):
137+
return self.builder.computer
139138

140139

141140
def main():
@@ -151,21 +150,21 @@ if __name__ == '__main__':
151150

152151
The basic changes are the introduction of a builder *ComputerBuilder*, a director *HardwareEngineer*, and the step-by-step construction of a computer, which now supports different configurations (notice that *memory*, *hdd*, and *gpu* are parameters and not preconfigured). What do we need to do if we want to support the construction of tablets? Implement this as an exercise.
153152

154-
基本的改变是构造器*ComputerBuilder*的命令,
153+
基本的改变是构造器*ComputerBuilder*的命令,管理器*HardwareEngineer*,以及发具体命令的计算机,现在计算机可以支持不同的配置(注意参数memory,hdd,和gpu都未预先配置)。如果我们想要支持平板的质量该怎么做呢?你把实现这个目标当作练习。
155154

156155
You might also want to change the computer *serial_number* into something that is different for each computer, because as it is now it means that all computers will have the same serial number (which is impractical).
157156

158-
我们或许也想改变计算机的‘串号’
157+
你或许想过为每台电脑更改为不同的“序列号”,因为这样,现在就意味着所有的点都拥有相同的序列号了(这也是不切实际的)。
159158

160159
## Implementation 实现
161160
Let's see how we can use the Builder design pattern to make a pizza ordering application. The pizza example is particularly interesting because a pizza is prepared in steps that should follow a specific order. To add the sauce, you first need to prepare the dough. To add the topping, you first need to add the sauce. And you can't start baking the pizza unless both the sauce and the topping are placed on the dough. Moreover, each pizza usually requires a different baking time, depending
162161
on the thickness of its dough and the topping used.
163162

164-
让我们来看一看,我们该如何使用构造器模式来编写一个披萨下单应用。披萨示例非常有趣,因为披萨的
163+
让我们来看一看,我们该如何使用构造器模式来编写一个披萨下单应用。披萨示例非常有趣,因为披萨要按照指定的订单一步一步地准备。要添加酱料的话,首先你需要准备生面团。要添加浇头,首先你需要放酱料。除非你把酱料和浇头都放到生面团上面否则你是没办法烘培披萨的。此外,通常,视面饼的厚度和浇头的使用,每个披萨都需要的不同的烘培时间。
165164

166165
We start with importing the required modules and declaring a few Enum parameters [j.mp/pytenum] plus a constant that are used many times in the application. The STEP_DELAY constant is used to add a time delay between the different steps of preparing a pizza (prepare the dough, add the sauce, and so on) as follows:
167166

168-
我们开始导入所需的模块,并声明了几个
167+
我们从导入所需的模块开始,然后声明了几个Enum参数[j.mp/pytenum],添加了在应用中多次应用的常量。如下, STEP_DELAY常量被用来在准备披萨(准备生面团,添加酱料,等等)的不同步骤中添加一个时间延迟:
169168

170169
```python
171170
from enum import Enum
@@ -179,13 +178,13 @@ from enum import Enum
179178
Our end product is a *pizza*, which is described by the *Pizza* class. When using the Builder pattern, the end product does not have many responsibilities, since it is
180179
not supposed to be instantiated directly. A builder creates an instance of the end product and makes sure that it is properly prepared. That is why the *Pizza* class is so minimal. It basically initializes all data to sane default values. An exception is the *prepare_dough()* method. The *prepare_dough()* method is defined in the *Pizza* class instead of a builder for two reasons:
181180

182-
我们最终的产品是‘披萨’,它由*Pizza*类描述。在使用构造器模式时,终端产品并没有
181+
我们最终的产品是‘披萨’,它由*Pizza*类描述。在使用构造器模式时,终端产品并没有太多的责任,因为它不支持直接实例化。构造器创建终端产品的实例,以保证披萨正确备料了。这就是为什么*Pizza*类这么细小的原因。基本上这个类初始化所有数据,以唤醒默认值。处理异常的方法是*prepare_dough()**prepare_dough()*方法定义在了*Pizza*类而不是构造器中有两个理由:
183182

184183
- To clarify the fact that the end product is typically minimal does not mean that you should never assign it any responsibilities
185184
- To promote code reuse through composition [GOF95, page 32]
186185

187-
- 为了理清终端产品的情况,
188-
-
186+
- 要说明的是,终端产品通畅是最小化的,但是这并不意味着你从此就不能让它承担任何的职责
187+
- 通过使用合成来提升代码的复用性
189188

190189
```python
191190
class Pizza:
@@ -216,6 +215,7 @@ class MargaritaBuilder:
216215
self.pizza = Pizza('margarita')
217216
self.progress = PizzaProgress.queued
218217
self.baking_time = 5 # in seconds for the sake of the example
218+
# 因为考虑到示例所以这里使用了秒
219219
def prepare_dough(self):
220220
self.progress = PizzaProgress.preparation
221221
self.pizza.prepare_dough(PizzaDough.thin)
@@ -269,7 +269,7 @@ class CreamyBaconBuilder:
269269

270270
The director in this example is the waiter. The core of the *Waiter* class is the *construct_pizza()* method, which accepts a builder as a parameter and executes all the pizza preparation steps in the right order. Choosing the appropriate builder, which can even be done in runtime, gives us the ability to create different pizza styles without modifying any code of the director (*Waiter*). The Waiter class also contains the *pizza()* method, which returns the end product (prepared pizza) as a variable to the caller as follows:
271271

272-
这个例子中的负责人是服务员*Waiter*类的核心是*construct_pizza()*方法,这个方法接受一个构造器并作为参数,然后按照正确的顺序执行所有的披萨预备工作。选择合适的构造器,甚至可以在运行时实现,构造器给予我们能够不用修改负责人(Waiter)的任何代码就可以常见不同风味的披萨。
272+
这个例子中的管理器是服务员*Waiter*类的核心是*construct_pizza()*方法,这个方法接受一个构造器并作为参数,然后按照正确的顺序执行所有的披萨预备工作。选择合适的构造器,甚至可以在运行时实现,构造器给予我们能够不用修改管理器(Waiter)的任何代码就可以常见不同风味的披萨。
273273

274274
```python
275275
class Waiter:

第五章-装饰器模式.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ Python的装饰器和装饰器模式之间不存在一对一的关系。Python
3737

3838
`sourcemaking.com`提供的下图,展示了我们如何利用特殊的部件来`装饰`一把枪以使枪消音,更加精确,具有杀伤性。注意此图使用的是子类化,不过在Python中,这不是必须的,因为我们可以利用该语言的内建装饰器功能。
3939

40-
图片
40+
![img](images/)
4141

4242
## 软件的例子
4343
Django框架使用装饰器来实现良好的扩展。例子就是视图装饰器。Django的`视图`装饰器可以用于:

0 commit comments

Comments
 (0)