@@ -130,7 +130,8 @@ There are often several options.
130
130
as separate classes from the main ``Logger `` class.
131
131
132
132
To keep our example here simple,
133
- let’s split out the handler:
133
+ let’s split out the handler
134
+ and leave filtering in the superclass.
134
135
135
136
code
136
137
@@ -145,29 +146,98 @@ and then compose them together:
145
146
146
147
code
147
148
148
- The result is quite elegant,
149
- and can result in an API that feels very much like a Lego set.
150
- A box of useful classes is provided to the programmer
151
- that can snap together to create complex configurations
152
- out of simple pieces.
149
+ The result is quite elegant —
150
+ an API that offers separately configurable classes
151
+ that click cleanly together to make a working logger.
153
152
154
153
Dodge: use multiple inheritance
155
154
-------------------------------
156
155
157
- problem is init methods
156
+ Instead of decomposing a complicated class into simpler classes,
157
+ some Python programmers try to combine the features
158
+ of several subclasses by using multiple inheritance:
159
+
160
+ code
161
+
162
+ A first obstacle is that multiple inheritance
163
+ will not always produce working code.
164
+ We were lucky in this case
165
+ that only Emit needed to completely rewrite log(),
166
+ while Filter was able to use super()
167
+ to delegate the actual message printing to its superclass.
168
+ If both subclasses had needed to entirely rewrite log(),
169
+ then their two implementations of the method
170
+ would not have cooperated at all.
171
+ And even in their current state,
172
+ our subclass only works because we listed Filter before Emit
173
+ in our base classes;
174
+ if the order were reversed, the class’s features would not compose.
175
+
176
+ Second, __init__() methods are notorious in Python
177
+ for the problems they cause for multiple inheritance.
178
+
179
+
180
+ not always possible
181
+
182
+ init parameters no longer compatible
183
+
184
+ init fragile and can break later?
185
+
186
+
158
187
159
188
Dodge: decompose into methods instead of classes
160
189
------------------------------------------------
161
190
162
- Some classes try to dodge the problems that the Bridge Pattern solves
163
- by decomposing a complicated class’s code into separate methods.
164
- Given our example,
165
- this approach would recognize that filtering and emitting
166
- are separate steps that will often need separate customization,
167
- but would grant them each a method instead of a class:
191
+ Instead of decomposing a complicated class into several classes,
192
+ some designers try to split its operations into separate methods instead.
193
+ In our example,
194
+ the two steps of filtering and emitting
195
+ would each be granted its own method:
168
196
169
197
example
170
198
199
+ This prevents new filter code and new output code
200
+ from trying to override the same method
201
+ and colliding with each other.
202
+ Instead, the code for each operation is cleanly separated.
203
+
204
+ example
205
+
206
+ Given the modularity of these replacement methods,
207
+ some programmers opt to provide them as standalone “mixins”
208
+ that don’t inherit from the base class
209
+ and can’t operate as standalone loggers themselves.
210
+ This forces the programmer to always build a class of their own.
211
+
212
+ example
213
+
214
+ But there are disadvantages
215
+ to decomposing several design axes
216
+ into mere methods rather than fully separate classes.
217
+
218
+ First,
219
+ class instances are easier to compose at runtime
220
+ than are class objects themselves.
221
+ Imagine that logging will now be driven by a configuration file.
222
+ The configuration will choose one logger for writing,
223
+ and how they are filtered.
224
+ How will Python code build a logger?
225
+
226
+ if fully decomposed easy
227
+ choose and instantiate a filter
228
+ choose and inst the logger,
229
+ passing it the filter.
230
+ A filter and printer can be combined at runtime quite simply,
231
+ by instantiating one and passing it to the other.
232
+
233
+ but a logging system freighted with mixin or m i system
234
+ will require the filter and printer
235
+ to be composed into a single class
236
+ The programmer will either need to instantiate ahead of time
237
+ all _m×n_ possible combinations of filters and printers,
238
+ or else build classes ahead of time.
239
+ (See the Appendix below for the details.)
240
+
171
241
problem
172
242
still remains complicated
173
243
what is its job “everything”
@@ -214,6 +284,9 @@ Appendix: functions instead of classes
214
284
215
285
216
286
287
+
288
+
289
+
217
290
object oriented folks will have seen situations
218
291
where a single class needs to be specialized
219
292
along many different axes at once
0 commit comments