Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 6fbfe54

Browse files
Start working on Bridge
1 parent 13a300a commit 6fbfe54

File tree

2 files changed

+249
-0
lines changed

2 files changed

+249
-0
lines changed

gang-of-four/bridge/index.rst

Lines changed: 248 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,248 @@
1+
2+
====================
3+
The Bridge Pattern
4+
====================
5+
6+
*A “Structural Pattern” from the* :doc:`/gang-of-four/index`
7+
8+
.. admonition:: Verdict
9+
10+
The Bridge Pattern solves the problem
11+
:
12+
instead of coupling
13+
14+
uncooperative subclasses
15+
========================
16+
17+
.. testcode::
18+
19+
class Logger(object):
20+
def log(self, level, message):
21+
print(level, message, file=sys.stderr)
22+
23+
two subclasses
24+
25+
.. testcode::
26+
27+
class FilteredLogger(Logger):
28+
def __init__(self, threshold):
29+
self.threshold = threshold
30+
31+
def log(self, level, message):
32+
if level >= threshold:
33+
print(level, message, file=sys.stderr)
34+
35+
class FileLogger(Logger):
36+
def __init__(self, file):
37+
self.file = file
38+
39+
def log(self, level, message):
40+
print(level, message, file=self.file)
41+
42+
can we do both?
43+
no!
44+
neither subclass defers to parent
45+
if we want a FilteredFileLogger
46+
there is no way to get there from FileLogger
47+
because it hard-codes sys.stderr
48+
49+
we will have to build it atop the FileLogger
50+
by copying the threshold test
51+
52+
.. testcode::
53+
54+
class FilteredFileLogger(FileLogger):
55+
def __init__(self, level, file):
56+
self.level = level
57+
super().__init__(file)
58+
59+
def log(self, level, message):
60+
if level >= threshold:
61+
super().log(level, message)
62+
63+
note the naming order
64+
put filtered first to remember both the order of operations
65+
and also the order of parameters during instantiation
66+
67+
in general code reuse is difficult
68+
we have had to re-implement filtering
69+
in a new subclass
70+
71+
Cooperative Subclasses
72+
======================
73+
74+
75+
76+
class FilteredLogger2(Logger):
77+
def __init__(self, threshold):
78+
self.threshold = threshold
79+
80+
def log(self, level, message):
81+
if level >= threshold:
82+
super().log(level, message)
83+
84+
here subclass has anticipated composition
85+
86+
class
87+
88+
note that this would have been a disaster
89+
if either subclass __init__ had called super().__init__()
90+
because they would have tried calling their fellow subclass
91+
92+
93+
94+
Cooperative Subclasses
95+
======================
96+
97+
you can design a class
98+
with specialization in mind
99+
like
100+
101+
.. testcode::
102+
103+
class BaseLogger(object):
104+
def log(self, level, message):
105+
level, message = self.filter(message)
106+
self.emit(level, message)
107+
108+
def emit(self, level, message):
109+
print(level, message, file=sys.stderr)
110+
111+
we could now do stuff without as much problem
112+
we wouldn’t have to worry about order of subclasses?
113+
hmm
114+
115+
the Bridge Pattern
116+
==================
117+
118+
119+
.. testcode::
120+
121+
class Logger(object):
122+
def __init__(self, handler):
123+
self.handler = handler
124+
125+
def log(self, level, message):
126+
self.handler(level, message)
127+
128+
class Handler(object):
129+
def log(self, level, message):
130+
self.handler(level, message)
131+
132+
now subclass independently
133+
134+
.. testcode::
135+
136+
class FilteredLogger(object):
137+
def __init__(self, handler, level):
138+
self.level = level
139+
super().__init__(level)
140+
141+
def log(self, level, message):
142+
if level >= foo:
143+
super().log(level, message)
144+
145+
class FileHandler(object):
146+
def __init__(self, file):
147+
self.file = file
148+
super().__init__()
149+
150+
def log(self, level, message):
151+
super considered super
152+
153+
== multiple inheritance works poorly
154+
if the stack of methods have different arguments
155+
156+
== we can think of ways around: instead of __init__ methods,
157+
have set_file() and set_level() methods
158+
that are called after instantiation
159+
160+
all the problems are solved
161+
162+
- no multiple inheritance
163+
164+
- therefore, init becomes safe again
165+
each class knows its superclass
166+
it can declare init that extends the superclass’s list of arguments
167+
with the additional arguments it needs
168+
and safely call super() init
169+
170+
171+
actual logging module more complicated
172+
173+
- expects subclasses, in fact requires it
174+
because handler offers but does not implement emit()
175+
several pre-made Handler classes
176+
177+
- makes the Handler complicated
178+
because not only does each Logger have its own stack of filters
179+
but each Handler can have a second stack of filters
180+
that get applied before it calls its own emit()
181+
so the logging module Handler
182+
is more like the Logger we defined above
183+
184+
- in another application of the Builder,
185+
separates out formatting into its own class as well
186+
187+
188+
189+
vvvvv keep this example of using actual?
190+
191+
.. testcode::
192+
193+
from logging import getLogger
194+
import logging
195+
196+
log = getLogger('example')
197+
198+
class FileHandler(logging.Handler):
199+
def __init__(self, file):
200+
self.file = file
201+
super().__init__()
202+
203+
def emit(self, record):
204+
print(self.file)
205+
print(repr(record))
206+
print(repr(record), file=self.file)
207+
208+
fh = FileHandler(open('/tmp/log.txt', 'w'))
209+
log.addHandler(fh)
210+
log.error('Warning!')
211+
212+
213+
214+
not using classes
215+
=================
216+
217+
would it be simpler not to use classes
218+
219+
with Thread the original mechanism has all but
220+
very few projects choose to subclass Thread any more
221+
and instead provide a callable
222+
223+
why not do that with logging?
224+
225+
.. testcode::
226+
227+
def make_filter(threshold):
228+
def filter(level, message):
229+
for level, message in messages:
230+
if level < messages:
231+
yield level, message
232+
return filter
233+
234+
235+
236+
answer: introspection
237+
238+
239+
240+
logging_tree
241+
242+
if logging wanted a less heavyweight approach
243+
could move to a data structure
244+
245+
.. testcode::
246+
247+
example = {
248+
'filters'

index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ Structural Patterns
5959
.. toctree::
6060
:maxdepth: 2
6161

62+
gang-of-four/bridge/index
6263
gang-of-four/composite/index
6364
gang-of-four/decorator-pattern/index
6465
gang-of-four/flyweight/index

0 commit comments

Comments
 (0)