Skip to content

Commit d080a67

Browse files
m-lm-l
m-l
authored and
m-l
committed
更新本章段第三段和第五段
1 parent a5df233 commit d080a67

File tree

1 file changed

+41
-28
lines changed

1 file changed

+41
-28
lines changed

第三章-原型模式.md

Lines changed: 41 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,14 @@ Sometimes, we need to create an exact copy of an object. For instance, assume
44
that you want to create an application for storing, sharing, and editing (such as modifying, adding notes, and removing) culinary recipes. User Bob finds a cake recipe and after making a few modifications he thinks that his cake is delicious, and he wants to share it with his friend, Alice. But what does sharing a recipe mean?
55
If Bob wants to do some further experimentation with his recipe after sharing it with Alice, will the new changes also be visible in Alice's recipe? Can Bob keep two copies of the cake recipe? His delicious cake recipe should remain unaffected by any changes made in the experimental cake recipe.
66

7-
Such problems can be solved by allowing the users to have more than one independent copy of the same recipe. Each copy is called a clone, because it is
8-
an exact copy of the original object at a specific point in time. The time aspect is important, since it affects what the clone contains. For example, if Bob shares the cake recipe with Alice before making his own improvements to achieve perfection, Alice will never be able to bake her own version of the delicious cake that Bob created! She will only be able to bake the original cake recipe found by Bob.
7+
有时候,我们需要创建一个对象的完全拷贝。例如,假设你想要创建一个能够存储、分享、和编辑的(比如,修改,添加笔记、删除笔记)菜谱应用。用户Bod发现了一本糕点食谱,
8+
9+
Such problems can be solved by allowing the users to have more than one independent copy of the same recipe. Each copy is called a clone, because it is an exact copy of the original object at a specific point in time. The time aspect is important, since it affects what the clone contains. For example, if Bob shares the cake recipe with Alice before making his own improvements to achieve perfection, Alice will never be able to bake her own version of the delicious cake that Bob created! She will only be able to bake the original cake recipe found by Bob.
910

1011
Note the difference between a copy and a reference. If we have two references to the same cake recipe, whatever changes Bob makes to the recipe will be visible to Alice's version of the recipe, and vice versa. What we want is both Bob and Alice to have their own copy, so that they can make independent changes without affecting each other's recipe. Bob actually needs two copies of the cake recipe: the delicious version and the experimental version.
1112

13+
注意拷贝和引用之间的不同。如果对相同的糕点食谱做了两个引用,不论Bob对食谱做了什么更改,Alice的食谱中都可以看到,反之亦然。要是我们想让Bob和Alice都拥有各自的拷贝,那么他们就可以各自变更而不影响到对方的食谱。Bob实际上需要糕点食谱的两份拷贝:美味版和体验版。
14+
1215
The difference between a reference and a copy is shown in the following figure:
1316

1417
引用和复制之间的区别如下图所示:
@@ -17,26 +20,35 @@ The difference between a reference and a copy is shown in the following figure:
1720

1821
On the left part, we can see two references. Both Alice and Bob refer to the same recipe, which essentially means that they share it and all modifications are visible by both. On the right part, we can see two different copies of the same recipe. In this case, independent modifications are allowed and the changes of Alice do not affect the changes of Bob, and vice versa.
1922

20-
The **Prototype design pattern** helps us with creating object clones. In its simplest version, the Prototype pattern is just a clone() function that accepts an object as
21-
an input parameter and returns a clone of it. In Python, this can be done using the copy.deepcopy() function. Let's see an example. In the following code (file clone. py), there are two classes, A and B. A is the parent class and B is the derived class. In the main part, we create an instance of class B b, and use deepcopy() to create a clone of b named c. The result is that all the members of the hierarchy (at the point of time the cloning happens) are copied in the clone c. As an interesting exercise, you can try using deepcopy() with composition instead of inheritance which is shown in the following code:
23+
在最后一部分,我们看到了两个引用。Alice和Bod引用了相同的食谱,这基本上就意味着他们共享了所有的变更,而且这些变更彼此课件。在右边部分,我们可以看到相同食谱的两份不同拷贝。这种情况下,单独的修改是被允许的,Alice的修改不会影响到Boo,反之亦然。
24+
25+
The **Prototype design pattern** helps us with creating object clones. In its simplest version, the Prototype pattern is just a clone() function that accepts an object as an input parameter and returns a clone of it. In Python, this can be done using the copy.deepcopy() function. Let's see an example. In the following code (file clone. py), there are two classes, A and B. A is the parent class and B is the derived class. In the main part, we create an instance of class B b, and use deepcopy() to create a clone of b named c. The result is that all the members of the hierarchy (at the point of time the cloning happens) are copied in the clone c. As an interesting exercise, you can try using deepcopy() with composition instead of inheritance which is shown in the following code:
26+
27+
圆形设计模式有助于我们创建一个对象的克隆。
2228

2329
```python
2430
import copy
31+
32+
2533
class A:
2634
def __init__(self):
2735
self.x = 18
2836
self.msg = 'Hello'
37+
38+
2939
class B(A):
3040
def __init__(self):
3141
A.__init__(self)
3242
self.y = 34
3343
def __str__(self):
3444
return '{}, {}, {}'.format(self.x, self.msg, self.y)
35-
if __name__ == '__main__':
36-
b = B()
37-
c = copy.deepcopy(b)
38-
print([str(i) for i in (b, c)])
39-
print([i for i in (b, c)])
45+
46+
47+
if __name__ == '__main__':
48+
b = B()
49+
c = copy.deepcopy(b)
50+
print([str(i) for i in (b, c)])
51+
print([i for i in (b, c)])
4052
```
4153

4254
When executing clone.py on my computer, I get the following:
@@ -89,17 +101,14 @@ as follows:
89101

90102
Can you think of any examples where using shallow copies is better than using deep copies?
91103

92-
## Implementation
93-
In programming, it is not uncommon for a book to be available in multiple editions. For example, the classic textbook on C programming The C Programming Language by Kernighan and Ritchie is available in two editions. The first edition was published
94-
in 1978. At that time, C was not standardized. The second edition of the book was published 10 years later and covers the standard (ANSI) version of C. What are
95-
the differences between the two editions? To mention a few, the price, the length (number of pages), and the publication date. But there are also many similarities: the authors, the publishers, and the tags/keywords that describe the book are exactly the same. This indicates that creating a new book from scratch is not always the best approach. If we know that there are many similarities between two book editions, we can use cloning and modify only the different parts of the new edition.
104+
## Implementation 实现
105+
In programming, it is not uncommon for a book to be available in multiple editions. For example, the classic textbook on C programming The C Programming Language by Kernighan and Ritchie is available in two editions. The first edition was published in 1978. At that time, C was not standardized. The second edition of the book was published 10 years later and covers the standard (ANSI) version of C. What are the differences between the two editions? To mention a few, the price, the length (number of pages), and the publication date. But there are also many similarities: the authors, the publishers, and the tags/keywords that describe the book are exactly the same. This indicates that creating a new book from scratch is not always the best approach. If we know that there are many similarities between two book editions, we can use cloning and modify only the different parts of the new edition.
96106

97-
Let's see how we can use the Prototype pattern for creating an application that shows book information. We begin with the representation of a book. Apart from the usual initialization, the Book class demonstrates an interesting technique. It shows how we can avoid the telescopic constructor problem. In the __init__() method, only three parameters are fixed: name, authors, and price. But clients can pass more parameters in the form of keywords (name=value) using the rest variable-length list. The line self.__dict__.update(rest) adds the contents of rest to the internal dictionary of the Book class to make them part of it.
107+
Let's see how we can use the Prototype pattern for creating an application that shows book information. We begin with the representation of a book. Apart from the usual initialization, the Book class demonstrates an interesting technique. It shows how we can avoid the telescopic constructor problem. In the `__init__()` method, only three parameters are fixed: name, authors, and price. But clients can pass more parameters in the form of keywords (name=value) using the rest variable-length list. The line `self.__dict__.update(rest)` adds the contents of rest to the internal dictionary of the Book class to make them part of it.
98108

99-
But there's a catch. Since we don't know all the names of the added parameters, we need to access the internal dict for making use of them in __str__(). And since the contents of a dictionary do not follow any specific order, we use an OrderedDict to force an order; otherwise, every time the program is executed, different outputs will be shown. Of course, you should not take my words for granted. As an exercise, remove the usage of OrderedDict and sorted() and run the example to see if I'm right:
109+
But there's a catch. Since we don't know all the names of the added parameters, we need to access the internal dict for making use of them in `__str__()`. And since the contents of a dictionary do not follow any specific order, we use an OrderedDict to force an order; otherwise, every time the program is executed, different outputs will be shown. Of course, you should not take my words for granted. As an exercise, remove the usage of OrderedDict and sorted() and run the example to see if I'm right:
100110

101111
```python
102-
103112
class Book:
104113
def __init__(self, name, authors, price, **rest):
105114
'''Examples of rest: publisher, length, tags, publication
@@ -123,7 +132,7 @@ But there's a catch. Since we don't know all the names of the added parameters,
123132
The `Prototype` class implements the Prototype design pattern. The heart of the Prototype class is the clone() method, which does the actual cloning using the familiar copy.deepcopy() function. But the Prototype class does a bit more than supporting cloning. It contains the register() and unregister() methods, which can be used to keep track of the objects that are cloned in a dictionary. Note that this is just a convenience, and not a necessity.
124133

125134

126-
Moreover, the clone() method uses the same trick that __str__() uses in the Book class, but this time for a different reason. Using the variable-length list attr, we can pass only the variables that really need to be modified when cloning an object as follows:
135+
Moreover, the `clone()` method uses the same trick that `__str__()` uses in the Book class, but this time for a different reason. Using the variable-length list attr, we can pass only the variables that really need to be modified when cloning an object as follows:
127136

128137
```python
129138
class Prototype:
@@ -136,8 +145,7 @@ class Prototype:
136145
def clone(self, identifier, **attr):
137146
found = self.objects.get(identifier)
138147
if not found:
139-
raise ValueError('Incorrect object identifier:
140-
{}'.format(identifier))
148+
raise ValueError('Incorrect object identifier:{}'.format(identifier))
141149
obj = copy.deepcopy(found)
142150
obj.__dict__.update(attr)
143151
return obj
@@ -154,8 +162,7 @@ def main():
154162
prototype = Prototype()
155163
cid = 'k&r-first'
156164
prototype.register(cid, b1)
157-
b2 = prototype.clone(cid, name='The C Programming Language
158-
(ANSI)', price=48.99, length=274,
165+
b2 = prototype.clone(cid, name='The C Programming Language(ANSI)', price=48.99, length=274,
159166
publication_date='1988-04-01', edition=2)
160167
for i in (b1, b2):
161168
print(i)
@@ -169,7 +176,9 @@ The `prototype.py` file is as follows:
169176

170177
```python
171178
import copy
172-
from collections import OrderedDict
179+
from collections import OrderedDict
180+
181+
173182
class Book:
174183
def __init__(self, name, authors, price, **rest):
175184
'''Examples of rest: publisher, length, tags, publication
@@ -187,6 +196,8 @@ import copy
187196
mylist.append('$')
188197
mylist.append('\n')
189198
return ''.join(mylist)
199+
200+
190201
class Prototype:
191202
def __init__(self):
192203
self.objects = dict()
@@ -197,11 +208,12 @@ import copy
197208
def clone(self, identifier, **attr):
198209
found = self.objects.get(identifier)
199210
if not found:
200-
raise ValueError('Incorrect object identifier:
201-
{}'.format(identifier))
211+
raise ValueError('Incorrect object identifier:{}'.format(identifier))
202212
obj = copy.deepcopy(found)
203213
obj.__dict__.update(attr)
204-
return obj
214+
return obj
215+
216+
205217
def main():
206218
b1 = Book('The C Programming Language', ('Brian W. Kernighan',
207219
'Dennis M.Ritchie'), price=118, publisher='Prentice Hall',
@@ -210,12 +222,13 @@ return obj
210222
prototype = Prototype()
211223
cid = 'k&r-first'
212224
prototype.register(cid, b1)
213-
b2 = prototype.clone(cid, name='The C Programming Language
214-
(ANSI)', price=48.99, length=274,
225+
b2 = prototype.clone(cid, name='The C Programming Language (ANSI)', price=48.99, length=274,
215226
publication_date='1988-04-01', edition=2)
216227
for i in (b1, b2):
217228
print(i)
218229
print("ID b1 : {} != ID b2 : {}".format(id(b1), id(b2)))
230+
231+
219232
if __name__ == '__main__':
220233
main()
221234
```
@@ -268,7 +281,7 @@ In the first case, we want to focus on improving the performance and the memory
268281

269282
在第一个例子中,我们希望将注意力放在通过引入对象之间的数据共享对以提高性能以及内存利用上面。但是修改数据时我们需要特别小心,因为这些修改对于所有的复制都是可见的。本章我们不会介绍浅拷贝的,不过你可以自己了解了解。
270283

271-
In the second case, we want to be able to make modifications to one copy without affecting the rest. That's useful for cases like the cake-recipe example that we have seen. Here, no data sharing is done and so we need to be careful about the resource consumption and the overhead that is introduced by our clones.
284+
In the second case, we want to be able to make modifications to one copy without affecting the rest. That is useful for cases like the cake-recipe example that we have seen. Here, no data sharing is done and so we need to be careful about the resource consumption and the overhead that is introduced by our clones.
272285

273286
在第二个例子中,我们徐昂能够修改一个副本而不会影响到余下的副本。
274287

0 commit comments

Comments
 (0)