~justin-fathomdb/nova/justinsb-openstack-api-volumes

« back to all changes in this revision

Viewing changes to vendor/Twisted-10.0.0/doc/core/howto/components.html

  • Committer: Jesse Andrews
  • Date: 2010-05-28 06:05:26 UTC
  • Revision ID: git-v1:bf6e6e718cdc7488e2da87b21e258ccc065fe499
initial commit

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
<?xml version="1.0" encoding="utf-8"?><!DOCTYPE html  PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN'  'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'><html lang="en" xmlns="http://www.w3.org/1999/xhtml">
 
2
  <head>
 
3
<title>Twisted Documentation: Components: Interfaces and Adapters</title>
 
4
<link href="stylesheet.css" rel="stylesheet" type="text/css"/>
 
5
  </head>
 
6
 
 
7
  <body bgcolor="white">
 
8
    <h1 class="title">Components: Interfaces and Adapters</h1>
 
9
    <div class="toc"><ol><li><a href="#auto0">Interfaces and Components in Twisted code</a></li><ul><li><a href="#auto1">Components and Inheritance</a></li></ul></ol></div>
 
10
    <div class="content">
 
11
<span/>
 
12
 
 
13
<p>Object oriented programming languages allow programmers to reuse portions of
 
14
existing code by creating new <q>classes</q> of objects which subclass another
 
15
class.  When a class subclasses another, it is said to <em>inherit</em> all of its
 
16
behaviour.  The subclass can then <q>override</q> and <q>extend</q> the behavior
 
17
provided to it by the superclass. Inheritance is very useful in many situations,
 
18
but because it is so convenient to use, often becomes abused in large software
 
19
systems, especially when multiple inheritance is involved. One solution is to
 
20
use <em>delegation</em> instead of <q>inheritance</q> where appropriate.
 
21
Delegation is simply the act of asking <em>another</em> object to perform a task
 
22
for an object. To support this design pattern, which is often referred to as the
 
23
<em>components</em> pattern because it involves many small interacting components,
 
24
<em>interfaces</em> and <em>adapters</em> were created by the Zope 3 team.</p>
 
25
 
 
26
<p><q>Interfaces</q> are simply markers which objects can use to say <q>I
 
27
implement this interface</q>. Other objects may then make requests like
 
28
<q>Please give me an object which implements interface X for object type Y</q>.
 
29
Objects which implement an interface for another object type are called
 
30
<q>adapters</q>.</p>
 
31
 
 
32
<p>The superclass-subclass relationship is said to be an <em>is-a</em> relationship.
 
33
When designing object hierarchies, object modellers use subclassing when they
 
34
can say that the subclass <em>is</em> the same class as the superclass. For
 
35
example:</p>
 
36
 
 
37
<pre class="python"><p class="py-linenumber"> 1
 
38
 2
 
39
 3
 
40
 4
 
41
 5
 
42
 6
 
43
 7
 
44
 8
 
45
 9
 
46
10
 
47
11
 
48
12
 
49
13
 
50
14
 
51
15
 
52
16
 
53
17
 
54
18
 
55
</p><span class="py-src-keyword">class</span> <span class="py-src-identifier">Shape</span>:
 
56
    <span class="py-src-variable">sideLength</span> = <span class="py-src-number">0</span>
 
57
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">getSideLength</span>(<span class="py-src-parameter">self</span>):
 
58
        <span class="py-src-keyword">return</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">sideLength</span>
 
59
    
 
60
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">setSideLength</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">sideLength</span>):
 
61
        <span class="py-src-variable">self</span>.<span class="py-src-variable">sideLength</span> = <span class="py-src-variable">sideLength</span>
 
62
 
 
63
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">area</span>(<span class="py-src-parameter">self</span>):
 
64
        <span class="py-src-keyword">raise</span> <span class="py-src-variable">NotImplementedError</span>, <span class="py-src-string">&quot;Subclasses must implement area&quot;</span>
 
65
  
 
66
<span class="py-src-keyword">class</span> <span class="py-src-identifier">Triangle</span>(<span class="py-src-parameter">Shape</span>):
 
67
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">area</span>(<span class="py-src-parameter">self</span>):
 
68
        <span class="py-src-keyword">return</span> (<span class="py-src-variable">self</span>.<span class="py-src-variable">sideLength</span> * <span class="py-src-variable">self</span>.<span class="py-src-variable">sideLength</span>) / <span class="py-src-number">2</span>
 
69
 
 
70
<span class="py-src-keyword">class</span> <span class="py-src-identifier">Square</span>(<span class="py-src-parameter">Shape</span>):
 
71
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">area</span>(<span class="py-src-parameter">self</span>):
 
72
        <span class="py-src-keyword">return</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">sideLength</span> * <span class="py-src-variable">self</span>.<span class="py-src-variable">sideLength</span>
 
73
</pre>
 
74
 
 
75
<p>In the above example, a Triangle <em>is-a</em> Shape, so it subclasses Shape,
 
76
and a Square <em>is-a</em> Shape, so it also subclasses Shape.</p>
 
77
 
 
78
<p>However, subclassing can get complicated, especially when Multiple
 
79
Inheritance enters the picture. Multiple Inheritance allows a class to inherit
 
80
from more than one base class. Software which relies heavily on inheritance
 
81
often ends up having both very wide and very deep inheritance trees, meaning
 
82
that one class inherits from many superclasses spread throughout the system.
 
83
Since subclassing with Multiple Inheritance means <em>implementation
 
84
inheritance</em>, locating a method's actual implementation and ensuring the
 
85
correct method is actually being invoked becomes a challenge. For example:</p>
 
86
 
 
87
<pre class="python"><p class="py-linenumber"> 1
 
88
 2
 
89
 3
 
90
 4
 
91
 5
 
92
 6
 
93
 7
 
94
 8
 
95
 9
 
96
10
 
97
11
 
98
12
 
99
13
 
100
14
 
101
15
 
102
16
 
103
17
 
104
18
 
105
19
 
106
20
 
107
21
 
108
22
 
109
</p><span class="py-src-keyword">class</span> <span class="py-src-identifier">Area</span>:
 
110
    <span class="py-src-variable">sideLength</span> = <span class="py-src-number">0</span>
 
111
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">getSideLength</span>(<span class="py-src-parameter">self</span>):
 
112
        <span class="py-src-keyword">return</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">sideLength</span>
 
113
    
 
114
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">setSideLength</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">sideLength</span>):
 
115
        <span class="py-src-variable">self</span>.<span class="py-src-variable">sideLength</span> = <span class="py-src-variable">sideLength</span>
 
116
 
 
117
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">area</span>(<span class="py-src-parameter">self</span>):
 
118
        <span class="py-src-keyword">raise</span> <span class="py-src-variable">NotImplementedError</span>, <span class="py-src-string">&quot;Subclasses must implement area&quot;</span>
 
119
 
 
120
<span class="py-src-keyword">class</span> <span class="py-src-identifier">Color</span>:
 
121
    <span class="py-src-variable">color</span> = <span class="py-src-variable">None</span>
 
122
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">setColor</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">color</span>):
 
123
      <span class="py-src-variable">self</span>.<span class="py-src-variable">color</span> = <span class="py-src-variable">color</span>
 
124
    
 
125
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">getColor</span>(<span class="py-src-parameter">self</span>):
 
126
      <span class="py-src-keyword">return</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">color</span>
 
127
 
 
128
<span class="py-src-keyword">class</span> <span class="py-src-identifier">Square</span>(<span class="py-src-parameter">Area</span>, <span class="py-src-parameter">Color</span>):
 
129
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">area</span>(<span class="py-src-parameter">self</span>):
 
130
        <span class="py-src-keyword">return</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">sideLength</span> * <span class="py-src-variable">self</span>.<span class="py-src-variable">sideLength</span>
 
131
</pre>
 
132
 
 
133
<p>The reason programmers like using implementation inheritance is because it
 
134
makes code easier to read since the implementation details of Area are in a
 
135
separate place than the implementation details of Color. This is nice, because
 
136
conceivably an object could have a color but not an area, or an area but not a
 
137
color. The problem, though, is that Square is not really an Area or a Color, but
 
138
has an area and color. Thus, we should really be using another object oriented
 
139
technique called <em>composition</em>, which relies on delegation rather than
 
140
inheritance to break code into small reusable chunks. Let us continue with the
 
141
Multiple Inheritance example, though, because it is often used in practice.</p>
 
142
 
 
143
<p>What if both the Color and the Area base class defined the same method,
 
144
perhaps <code>calculate</code>? Where would the implementation come from? The
 
145
implementation that is located for <code>Square().calculate()</code> depends on
 
146
the method resolution order, or MRO, and can change when programmers change
 
147
seemingly unrelated things by refactoring classes in other parts of the system,
 
148
causing obscure bugs. Our first thought might be to change the calculate method
 
149
name to avoid name clashes, to perhaps <code>calculateArea</code> and
 
150
<code>calculateColor</code>.  While explicit, this change could potentially
 
151
require a large number of changes throughout a system, and is error-prone,
 
152
especially when attempting to integrate two systems which you didn't write.</p>
 
153
 
 
154
<p>Let's imagine another example. We have an electric appliance, say a hair
 
155
dryer. The hair dryer is american voltage. We have two electric sockets, one of
 
156
them an american 110 Volt socket, and one of them a foreign 220 Volt socket. If
 
157
we plug the hair dryer into the 220 Volt socket, it is going to expect 110 Volt
 
158
current and errors will result. Going back and changing the hair dryer to
 
159
support both <code>plug110Volt</code> and <code>plug220Volt</code> methods would
 
160
be tedious, and what if we decided we needed to plug the hair dryer into yet
 
161
another type of socket? For example:</p>
 
162
 
 
163
<pre class="python"><p class="py-linenumber"> 1
 
164
 2
 
165
 3
 
166
 4
 
167
 5
 
168
 6
 
169
 7
 
170
 8
 
171
 9
 
172
10
 
173
11
 
174
12
 
175
13
 
176
14
 
177
15
 
178
</p><span class="py-src-keyword">class</span> <span class="py-src-identifier">HairDryer</span>:
 
179
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">plug</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">socket</span>):
 
180
        <span class="py-src-keyword">if</span> <span class="py-src-variable">socket</span>.<span class="py-src-variable">voltage</span>() == <span class="py-src-number">110</span>:
 
181
            <span class="py-src-keyword">print</span> <span class="py-src-string">&quot;I was plugged in properly and am operating.&quot;</span>
 
182
        <span class="py-src-keyword">else</span>:
 
183
            <span class="py-src-keyword">print</span> <span class="py-src-string">&quot;I was plugged in improperly and &quot;</span>
 
184
            <span class="py-src-keyword">print</span> <span class="py-src-string">&quot;now you have no hair dryer any more.&quot;</span>
 
185
 
 
186
<span class="py-src-keyword">class</span> <span class="py-src-identifier">AmericanSocket</span>:
 
187
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">voltage</span>(<span class="py-src-parameter">self</span>):
 
188
        <span class="py-src-keyword">return</span> <span class="py-src-number">110</span>
 
189
 
 
190
<span class="py-src-keyword">class</span> <span class="py-src-identifier">ForeignSocket</span>:
 
191
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">voltage</span>(<span class="py-src-parameter">self</span>):
 
192
        <span class="py-src-keyword">return</span> <span class="py-src-number">220</span>
 
193
</pre>
 
194
 
 
195
<p>Given these classes, the following operations can be performed:</p>
 
196
 
 
197
<pre class="python-interpreter" xml:space="preserve">
 
198
&gt;&gt;&gt; hd = HairDryer()
 
199
&gt;&gt;&gt; am = AmericanSocket()
 
200
&gt;&gt;&gt; hd.plug(am)
 
201
I was plugged in properly and am operating.
 
202
&gt;&gt;&gt; fs = ForeignSocket()
 
203
&gt;&gt;&gt; hd.plug(fs)
 
204
I was plugged in improperly and 
 
205
now you have no hair dryer any more.
 
206
</pre>
 
207
 
 
208
<p>We are going to attempt to solve this problem by writing an Adapter for the
 
209
<code>ForeignSocket</code> which converts the voltage for use with an American
 
210
hair dryer. An Adapter is a class which is constructed with one and only one
 
211
argument, the <q>adaptee</q> or <q>original</q> object. In this example, we
 
212
will show all code involved for clarity:</p>
 
213
 
 
214
<pre class="python"><p class="py-linenumber">1
 
215
2
 
216
3
 
217
4
 
218
5
 
219
6
 
220
</p><span class="py-src-keyword">class</span> <span class="py-src-identifier">AdaptToAmericanSocket</span>:
 
221
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">__init__</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">original</span>):
 
222
        <span class="py-src-variable">self</span>.<span class="py-src-variable">original</span> = <span class="py-src-variable">original</span>
 
223
    
 
224
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">voltage</span>(<span class="py-src-parameter">self</span>):
 
225
        <span class="py-src-keyword">return</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">original</span>.<span class="py-src-variable">voltage</span>() / <span class="py-src-number">2</span>
 
226
</pre>
 
227
 
 
228
<p>Now, we can use it as so:</p>
 
229
 
 
230
<pre class="python-interpreter" xml:space="preserve">
 
231
&gt;&gt;&gt; hd = HairDryer()
 
232
&gt;&gt;&gt; fs = ForeignSocket()
 
233
&gt;&gt;&gt; adapted = AdaptToAmericanSocket(fs)
 
234
&gt;&gt;&gt; hd.plug(adapted)
 
235
I was plugged in properly and am operating.
 
236
</pre>
 
237
 
 
238
<p>So, as you can see, an adapter can 'override' the original implementation. It
 
239
can also 'extend' the interface of the original object by providing methods the
 
240
original object did not have. Note that an Adapter must explicitly delegate any
 
241
method calls it does not wish to modify to the original, otherwise the Adapter
 
242
cannot be used in places where the original is expected. Usually this is not a
 
243
problem, as an Adapter is created to conform an object to a particular interface
 
244
and then discarded.</p>
 
245
 
 
246
<h2>Interfaces and Components in Twisted code<a name="auto0"/></h2>
 
247
 
 
248
<p>Adapters are a useful way of using multiple classes to factor code into
 
249
discrete chunks. However, they are not very interesting without some more
 
250
infrastructure. If each piece of code which wished to use an adapted object had
 
251
to explicitly construct the adapter itself, the coupling between components
 
252
would be too tight. We would like to achieve <q>loose coupling</q>, and this is
 
253
where <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.python.components.html" title="twisted.python.components">twisted.python.components</a></code> comes in.</p>
 
254
 
 
255
<p>First, we need to discuss Interfaces in more detail. As we mentioned
 
256
earlier, an Interface is nothing more than a class which is used as a marker.
 
257
Interfaces should be subclasses of <code>zope.interface.Interface</code>, and
 
258
have a very odd look to python programmers not used to them:</p>
 
259
 
 
260
<pre class="python"><p class="py-linenumber">1
 
261
2
 
262
3
 
263
4
 
264
5
 
265
6
 
266
</p><span class="py-src-keyword">from</span> <span class="py-src-variable">zope</span>.<span class="py-src-variable">interface</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Interface</span>
 
267
 
 
268
<span class="py-src-keyword">class</span> <span class="py-src-identifier">IAmericanSocket</span>(<span class="py-src-parameter">Interface</span>):
 
269
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">voltage</span>():
 
270
      <span class="py-src-string">&quot;&quot;&quot;Return the voltage produced by this socket object, as an integer.
 
271
      &quot;&quot;&quot;</span>
 
272
</pre>
 
273
 
 
274
<p>Notice how it looks just like a regular class definition, other than
 
275
inheriting from <code>Interface</code>? However, the method definitions inside
 
276
the class block do not have any method body! Since Python does not have any
 
277
native language-level support for Interfaces like Java does, this is what
 
278
distinguishes an Interface definition from a Class.</p>
 
279
 
 
280
<p>Now that we have a defined Interface, we can talk about objects using terms
 
281
like this: <q>The <code>AmericanSocket</code> class implements the
 
282
<code>IAmericanSocket</code> interface</q> and <q>Please give me an object which
 
283
adapts <code>ForeignSocket</code> to the <code>IAmericanSocket</code>
 
284
interface</q>. We can make <em>declarations</em> about what interfaces a certain
 
285
class implements, and we can request adapters which implement a certain
 
286
interface for a specific class.</p>
 
287
 
 
288
<p>Let's look at how we declare that a class implements an interface:</p>
 
289
 
 
290
<pre class="python"><p class="py-linenumber">1
 
291
2
 
292
3
 
293
4
 
294
5
 
295
6
 
296
7
 
297
8
 
298
</p><span class="py-src-keyword">from</span> <span class="py-src-variable">zope</span>.<span class="py-src-variable">interface</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">implements</span>
 
299
 
 
300
<span class="py-src-keyword">class</span> <span class="py-src-identifier">AmericanSocket</span>:
 
301
 
 
302
    <span class="py-src-variable">implements</span>(<span class="py-src-variable">IAmericanSocket</span>)
 
303
 
 
304
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">voltage</span>(<span class="py-src-parameter">self</span>):
 
305
        <span class="py-src-keyword">return</span> <span class="py-src-number">110</span>
 
306
</pre>
 
307
 
 
308
<p>So, to declare that a class implements an interface, we simply call
 
309
<code>zope.interface.implements</code> at the class level.</p>
 
310
 
 
311
<p>Now, let's say we want to rewrite the <code>AdaptToAmericanSocket</code>
 
312
class as a real adapter. In this case we also specify it as implementing
 
313
<code>IAmericanSocket</code>:</p>
 
314
 
 
315
<pre class="python"><p class="py-linenumber"> 1
 
316
 2
 
317
 3
 
318
 4
 
319
 5
 
320
 6
 
321
 7
 
322
 8
 
323
 9
 
324
10
 
325
11
 
326
12
 
327
13
 
328
14
 
329
</p><span class="py-src-keyword">from</span> <span class="py-src-variable">zope</span>.<span class="py-src-variable">interface</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">implements</span>
 
330
 
 
331
<span class="py-src-keyword">class</span> <span class="py-src-identifier">AdaptToAmericanSocket</span>:
 
332
 
 
333
    <span class="py-src-variable">implements</span>(<span class="py-src-variable">IAmericanSocket</span>)
 
334
 
 
335
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">__init__</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">original</span>):
 
336
        <span class="py-src-string">&quot;&quot;&quot;
 
337
        Pass the original ForeignSocket object as original
 
338
        &quot;&quot;&quot;</span>
 
339
        <span class="py-src-variable">self</span>.<span class="py-src-variable">original</span> = <span class="py-src-variable">original</span>
 
340
 
 
341
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">voltage</span>(<span class="py-src-parameter">self</span>):
 
342
        <span class="py-src-keyword">return</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">original</span>.<span class="py-src-variable">voltage</span>() / <span class="py-src-number">2</span>
 
343
</pre>
 
344
 
 
345
<p>Notice how we placed the implements declaration on this adapter class. So
 
346
far, we have not achieved anything by using components other than requiring us
 
347
to type more. In order for components to be useful, we must use the
 
348
<em>component registry</em>. Since <code>AdaptToAmericanSocket</code> implements
 
349
<code>IAmericanSocket</code> and regulates the voltage of a
 
350
<code>ForeignSocket</code> object, we can <em>register
 
351
<code>AdaptToAmericanSocket</code> as an <code>IAmericanSocket</code> adapter
 
352
for the <code>ForeignSocket</code> class</em>. It is easier to see how this is
 
353
done in code than to describe it:</p>
 
354
 
 
355
<pre class="python"><p class="py-linenumber"> 1
 
356
 2
 
357
 3
 
358
 4
 
359
 5
 
360
 6
 
361
 7
 
362
 8
 
363
 9
 
364
10
 
365
11
 
366
12
 
367
13
 
368
14
 
369
15
 
370
16
 
371
17
 
372
18
 
373
19
 
374
20
 
375
21
 
376
22
 
377
23
 
378
24
 
379
25
 
380
26
 
381
27
 
382
28
 
383
29
 
384
30
 
385
31
 
386
32
 
387
</p><span class="py-src-keyword">from</span> <span class="py-src-variable">zope</span>.<span class="py-src-variable">interface</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Interface</span>, <span class="py-src-variable">implements</span>
 
388
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">python</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">components</span>
 
389
 
 
390
<span class="py-src-keyword">class</span> <span class="py-src-identifier">IAmericanSocket</span>(<span class="py-src-parameter">Interface</span>):
 
391
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">voltage</span>():
 
392
      <span class="py-src-string">&quot;&quot;&quot;Return the voltage produced by this socket object, as an integer.
 
393
      &quot;&quot;&quot;</span>
 
394
    
 
395
<span class="py-src-keyword">class</span> <span class="py-src-identifier">AmericanSocket</span>:
 
396
    <span class="py-src-variable">implements</span>(<span class="py-src-variable">IAmericanSocket</span>)
 
397
 
 
398
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">voltage</span>(<span class="py-src-parameter">self</span>):
 
399
        <span class="py-src-keyword">return</span> <span class="py-src-number">110</span>
 
400
 
 
401
<span class="py-src-keyword">class</span> <span class="py-src-identifier">ForeignSocket</span>:
 
402
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">voltage</span>(<span class="py-src-parameter">self</span>):
 
403
        <span class="py-src-keyword">return</span> <span class="py-src-number">220</span>
 
404
 
 
405
<span class="py-src-keyword">class</span> <span class="py-src-identifier">AdaptToAmericanSocket</span>:
 
406
 
 
407
    <span class="py-src-variable">implements</span>(<span class="py-src-variable">IAmericanSocket</span>)
 
408
 
 
409
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">__init__</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">original</span>):
 
410
        <span class="py-src-variable">self</span>.<span class="py-src-variable">original</span> = <span class="py-src-variable">original</span>
 
411
 
 
412
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">voltage</span>(<span class="py-src-parameter">self</span>):
 
413
        <span class="py-src-keyword">return</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">original</span>.<span class="py-src-variable">voltage</span>() / <span class="py-src-number">2</span>
 
414
    
 
415
<span class="py-src-variable">components</span>.<span class="py-src-variable">registerAdapter</span>(
 
416
    <span class="py-src-variable">AdaptToAmericanSocket</span>, 
 
417
    <span class="py-src-variable">ForeignSocket</span>, 
 
418
    <span class="py-src-variable">IAmericanSocket</span>)
 
419
</pre>
 
420
 
 
421
<p>Now, if we run this script in the interactive interpreter, we can discover a
 
422
little more about how to use components. The first thing we can do is discover
 
423
whether an object implements an interface or not:</p>
 
424
 
 
425
<pre class="python-interpreter" xml:space="preserve">
 
426
&gt;&gt;&gt; IAmericanSocket.implementedBy(AmericanSocket)
 
427
True
 
428
&gt;&gt;&gt; IAmericanSocket.implementedBy(ForeignSocket)
 
429
False
 
430
&gt;&gt;&gt; am = AmericanSocket() 
 
431
&gt;&gt;&gt; fs = ForeignSocket()
 
432
&gt;&gt;&gt; IAmericanSocket.providedBy(am)
 
433
True
 
434
&gt;&gt;&gt; IAmericanSocket.providedBy(fs)
 
435
False
 
436
</pre>
 
437
 
 
438
<p>As you can see, the <code>AmericanSocket</code> instance claims to
 
439
implement <code>IAmericanSocket</code>, but the <code>ForeignSocket</code>
 
440
does not. If we wanted to use the <code>HairDryer</code> with the
 
441
<code>AmericanSocket</code>, we could know that it would be safe to do so by
 
442
checking whether it implements <code>IAmericanSocket</code>. However, if we
 
443
decide we want to use <code>HairDryer</code> with a <code>ForeignSocket</code>
 
444
instance, we must <em>adapt</em> it to <code>IAmericanSocket</code> before
 
445
doing so.  We use the interface object to do this:</p>
 
446
 
 
447
<pre class="python-interpreter" xml:space="preserve">
 
448
&gt;&gt;&gt; IAmericanSocket(fs)
 
449
&lt;__main__.AdaptToAmericanSocket instance at 0x1a5120&gt;
 
450
</pre>
 
451
 
 
452
<p>When calling an interface with an object as an argument, the interface
 
453
looks in the adapter registry for an adapter which implements the interface for
 
454
the given instance's class. If it finds one, it constructs an instance of the
 
455
Adapter class, passing the constructor the original instance, and returns it.
 
456
Now the <code>HairDryer</code> can safely be used with the adapted
 
457
<code>ForeignSocket</code>. But what happens if we attempt to adapt an object
 
458
which already implements <code>IAmericanSocket</code>? We simply get back the
 
459
original instance:</p>
 
460
 
 
461
<pre class="python-interpreter" xml:space="preserve">
 
462
&gt;&gt;&gt; IAmericanSocket(am)
 
463
&lt;__main__.AmericanSocket instance at 0x36bff0&gt;
 
464
</pre>
 
465
 
 
466
<p>So, we could write a new <q>smart</q> <code>HairDryer</code> which
 
467
automatically looked up an adapter for the socket you tried to plug it into:</p>
 
468
 
 
469
<pre class="python"><p class="py-linenumber">1
 
470
2
 
471
3
 
472
4
 
473
5
 
474
</p><span class="py-src-keyword">class</span> <span class="py-src-identifier">HairDryer</span>:
 
475
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">plug</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">socket</span>):
 
476
        <span class="py-src-variable">adapted</span> = <span class="py-src-variable">IAmericanSocket</span>(<span class="py-src-variable">socket</span>)
 
477
        <span class="py-src-keyword">assert</span> <span class="py-src-variable">adapted</span>.<span class="py-src-variable">voltage</span>() == <span class="py-src-number">110</span>, <span class="py-src-string">&quot;BOOM&quot;</span>
 
478
        <span class="py-src-keyword">print</span> <span class="py-src-string">&quot;I was plugged in properly and am operating&quot;</span>
 
479
</pre>
 
480
 
 
481
<p>Now, if we create an instance of our new <q>smart</q> <code>HairDryer</code>
 
482
and attempt to plug it in to various sockets, the <code>HairDryer</code> will
 
483
adapt itself automatically depending on the type of socket it is plugged in
 
484
to:</p>
 
485
 
 
486
<pre class="python-interpreter" xml:space="preserve">
 
487
&gt;&gt;&gt; am = AmericanSocket()
 
488
&gt;&gt;&gt; fs = ForeignSocket()
 
489
&gt;&gt;&gt; hd = HairDryer()
 
490
&gt;&gt;&gt; hd.plug(am)
 
491
I was plugged in properly and am operating
 
492
&gt;&gt;&gt; hd.plug(fs)
 
493
I was plugged in properly and am operating
 
494
</pre>
 
495
    
 
496
<p>Voila; the magic of components.</p>
 
497
 
 
498
<h3>Components and Inheritance<a name="auto1"/></h3>
 
499
 
 
500
<p>If you inherit from a class which implements some interface, and your new
 
501
subclass declares that it implements another interface, the implements will be
 
502
inherited by default.</p>
 
503
 
 
504
<p>For example, <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.spread.pb.Root.html" title="twisted.spread.pb.Root">pb.Root</a></code> is a class
 
505
which implements <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.spread.pb.IPBRoot.html" title="twisted.spread.pb.IPBRoot">IPBRoot</a></code>. This interface indicates that an
 
506
object has remotely-invokable methods and can be used as the initial object
 
507
served by a new Broker instance. It has an <code>implements</code> setting
 
508
like:</p>
 
509
 
 
510
<pre class="python"><p class="py-linenumber">1
 
511
2
 
512
3
 
513
4
 
514
</p><span class="py-src-keyword">from</span> <span class="py-src-variable">zope</span>.<span class="py-src-variable">interface</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">implements</span>
 
515
 
 
516
<span class="py-src-keyword">class</span> <span class="py-src-identifier">Root</span>(<span class="py-src-parameter">Referenceable</span>):
 
517
    <span class="py-src-variable">implements</span>(<span class="py-src-variable">IPBRoot</span>)
 
518
</pre>
 
519
 
 
520
<p>Suppose you have your own class which implements your
 
521
<code>IMyInterface</code> interface:</p>
 
522
 
 
523
<pre class="python"><p class="py-linenumber">1
 
524
2
 
525
3
 
526
4
 
527
5
 
528
6
 
529
7
 
530
</p><span class="py-src-keyword">from</span> <span class="py-src-variable">zope</span>.<span class="py-src-variable">interface</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">implements</span>, <span class="py-src-variable">Interface</span>
 
531
 
 
532
<span class="py-src-keyword">class</span> <span class="py-src-identifier">IMyInterface</span>(<span class="py-src-parameter">Interface</span>):
 
533
    <span class="py-src-keyword">pass</span>
 
534
 
 
535
<span class="py-src-keyword">class</span> <span class="py-src-identifier">MyThing</span>:
 
536
    <span class="py-src-variable">implements</span>(<span class="py-src-variable">IMyInterface</span>)
 
537
</pre>
 
538
 
 
539
<p>Now if you want to make this class inherit from <code>pb.Root</code>, 
 
540
the interfaces code will automatically determine that it also implements
 
541
<code>IPBRoot</code>:</p>
 
542
 
 
543
<pre class="python"><p class="py-linenumber">1
 
544
2
 
545
3
 
546
4
 
547
5
 
548
6
 
549
7
 
550
8
 
551
</p><span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">spread</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">pb</span>
 
552
<span class="py-src-keyword">from</span> <span class="py-src-variable">zope</span>.<span class="py-src-variable">interface</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">implements</span>, <span class="py-src-variable">Interface</span>
 
553
 
 
554
<span class="py-src-keyword">class</span> <span class="py-src-identifier">IMyInterface</span>(<span class="py-src-parameter">Interface</span>):
 
555
    <span class="py-src-keyword">pass</span>
 
556
 
 
557
<span class="py-src-keyword">class</span> <span class="py-src-identifier">MyThing</span>(<span class="py-src-parameter">pb</span>.<span class="py-src-parameter">Root</span>):
 
558
    <span class="py-src-variable">implements</span>(<span class="py-src-variable">IMyInterface</span>)
 
559
</pre>
 
560
 
 
561
<pre class="python-interpreter" xml:space="preserve">
 
562
&gt;&gt;&gt; from twisted.spread.flavors import IPBRoot
 
563
&gt;&gt;&gt; IPBRoot.implementedBy(MyThing)
 
564
True
 
565
</pre>
 
566
 
 
567
<p>If you want <code>MyThing</code> to inherit from <code>pb.Root</code> but
 
568
<em>not</em> implement <code>IPBRoot</code> like <code>pb.Root</code> does,
 
569
use <code>implementOnly</code>:</p>
 
570
 
 
571
<pre class="python"><p class="py-linenumber">1
 
572
2
 
573
3
 
574
4
 
575
5
 
576
6
 
577
7
 
578
8
 
579
</p><span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">spread</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">pb</span>
 
580
<span class="py-src-keyword">from</span> <span class="py-src-variable">zope</span>.<span class="py-src-variable">interface</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">implementsOnly</span>, <span class="py-src-variable">Interface</span>
 
581
 
 
582
<span class="py-src-keyword">class</span> <span class="py-src-identifier">IMyInterface</span>(<span class="py-src-parameter">Interface</span>):
 
583
    <span class="py-src-keyword">pass</span>
 
584
 
 
585
<span class="py-src-keyword">class</span> <span class="py-src-identifier">MyThing</span>(<span class="py-src-parameter">pb</span>.<span class="py-src-parameter">Root</span>):
 
586
    <span class="py-src-variable">implementsOnly</span>(<span class="py-src-variable">IMyInterface</span>)
 
587
</pre>
 
588
 
 
589
<pre class="python-interpreter" xml:space="preserve">
 
590
&gt;&gt;&gt; from twisted.spread.pb import IPBRoot
 
591
&gt;&gt;&gt; IPBRoot.implementedBy(MyThing)
 
592
False
 
593
</pre>
 
594
 
 
595
</div>
 
596
 
 
597
    <p><a href="index.html">Index</a></p>
 
598
    <span class="version">Version: 10.0.0</span>
 
599
  </body>
 
600
</html>
 
 
b'\\ No newline at end of file'