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
The Adapter pattern is used for making things work after they have been implemented [j.mp/adapterpat]. Usually one of the two incompatible interfaces is either foreign or old/legacy. If the interface is foreign, it means that we have no access to the source code. If it is old it is usually impractical to refactor it. We can take it even further and argue that altering the implementation of a legacy component to meet our needs is not only impractical, but it also violates the open/close principle [j.mp/adaptsimp]. The open/close principle is one of the fundamental principles of Object-Oriented design (the O of SOLID). It states that a software entity should
42
42
be open for extension, but closed for modi cation. That basically means that we should be able to extend the behavior of an entity without making source code modi cations. Adapter respects the open/closed principle [j.mp/openclosedp].
Therefore, using an Adapter for making things work after they have been implemented is a better approach because it:
47
47
@@ -56,11 +56,11 @@ Therefore, using an Adapter for making things work after they have been implemen
56
56
## Implementation 实现
57
57
There are many ways of implementing the Adapter design pattern in Python [Eckel08, page 207]. All the techniques demonstrated by Bruce Eckel use inheritance, but Python provides an alternative, and in my opinion, a more idiomatic way of implementing an Adapter. The alternative technique should be familiar to you, since it uses the internal dictionary of a class, and we have seen how to do that in Chapter 3, The Prototype Pattern.
Let's begin with the what we have part. Our application has a Computer class that shows basic information about a computer. All the classes of this example, including the Computer class are very primitive, because we want to focus on the Adapter pattern and not on how to make a class as complete as possible.
@@ -78,38 +78,49 @@ In this case, the execute() method is the main action that the computer can perf
78
78
79
79
Now we move to the what we want part. We decide to enrich our application with more functionality, and luckily, we nd two interesting classes implemented in two different libraries that are unrelated with our application: Synthesizer and Human. In the Synthesizer class, the main action is performed by the play() method. In the Human class, it is performed by the speak() method. To indicate that the two classes are external, we place them in a separate module, as shown:
So far so good. But, we have a problem. The client only knows how to call the execute() method, and it has no idea about play() or speak(). How can we make the code work without changing the Synthesizer and Human classes? Adapters to the rescue! We create a generic Adapter class that allows us to adapt a number of objects with different interfaces, into one uni ed interface. The obj argument of the __init__() method is the object that we want to adapt, and adapted_methods is a dictionary containing key/value pairs of method the client calls/method that should be called.
106
+
So far so good. But, we have a problem. The client only knows how to call the execute() method, and it has no idea about play() or speak(). How can we make the code work without changing the Synthesizer and Human classes? Adapters to the rescue! We create a generic Adapter class that allows us to adapt a number of objects with different interfaces, into one uni ed interface. The obj argument of the `__init__()` method is the object that we want to adapt, and adapted_methods is a dictionary containing key/value pairs of method the client calls/method that should be called.
Let's see how we can use the Adapter pattern. An objects list holds all the objects. The compatible objects that belong to the Computer class need no adaptation. We can add them directly to the list. The incompatible objects are not added directly. They are adapted using the Adapter class. The result is that the client code can continue using the known execute() method on all objects without the need to be aware of any interface differences between the used classes.
We managed to make the Human and Synthesizer classes compatible with the interface expected by the client, without changing their source code. This is nice.
178
211
Here's a challenging exercise for you. There is a problem with this implementation. While all classes have a name attribute, the following code fails:
179
212
213
+
我们希望由用户来管理
214
+
180
215
```python
181
216
for i in objects:
182
217
print(i.name)
183
218
```
184
219
185
220
First of all, why does this code fail? Although this makes sense from a coding point of view, it does not make sense at all for the client code which should not be aware of details such as what is adapted and what is not adapted. We just want to provide a uniform interface. How can we make this code work?
186
221
222
+
首先要说的是,这个代码为何会运行失败呢?
223
+
187
224
>### Tip
188
225
>Hint: Think of how you can delegate the non-adapted parts to the object contained in the Adapter class.
189
226
227
+
>### 提示
228
+
>想一想你该如何对包含在Adapter类中对象分配不适配的部分。
229
+
190
230
## Summary 总结
191
231
This chapter covered the Adapter design pattern. We use the Adapter pattern for making two (or more) incompatible interfaces compatible. As a motivation, an e-commerce system that should support multiple currencies was mentioned.
192
232
We use adapters every day for interconnecting devices, charging them, and so on.
Adapter makes things work after they have been implemented. The Grok Python framework and the Traits package use the Adapter pattern for achieving API conformance and interface compatibility, respectively. The open/close principle is strongly connected with these aspects.
In the implementation section, we saw how to achieve interface conformance using the Adapter pattern without modifying the source code of the incompatible model. This is achieved through a generic Adapter class that does the work for us. Although we could use sub-classing (inheritance) to implement the Adapter pattern in the traditional way in Python, this technique is a great alternative.
197
241
198
-
In the next chapter, we will see how we can use the Decorator pattern to extend the behavior of an object without using sub-classing.
242
+
在实现部分,我们见到了如何使用适配器模式实现接口一致,而不修改不兼容模型的源码。
199
243
244
+
In the next chapter, we will see how we can use the Decorator pattern to extend the behavior of an object without using sub-classing.
0 commit comments