You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: 第三章-原型模式.md
+41-28Lines changed: 41 additions & 28 deletions
Original file line number
Diff line number
Diff line change
@@ -4,11 +4,14 @@ Sometimes, we need to create an exact copy of an object. For instance, assume
4
4
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?
5
5
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.
6
6
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.
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.
9
10
10
11
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.
The difference between a reference and a copy is shown in the following figure:
13
16
14
17
引用和复制之间的区别如下图所示:
@@ -17,26 +20,35 @@ The difference between a reference and a copy is shown in the following figure:
17
20
18
21
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.
19
22
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:
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:
When executing clone.py on my computer, I get the following:
@@ -89,17 +101,14 @@ as follows:
89
101
90
102
Can you think of any examples where using shallow copies is better than using deep copies?
91
103
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.
96
106
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.
98
108
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:
100
110
101
111
```python
102
-
103
112
classBook:
104
113
def__init__(self, name, authors, price, **rest):
105
114
'''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,
123
132
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.
124
133
125
134
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:
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.
0 commit comments