桥接模式(Bridge Pattern)用于将”抽象”(abstraction, 比如接口或算法)与实现方式相分离。
如果不用桥接模式,那么通常的写法是,创建若干个基类,用于表示各种抽象方式,然后从每个基类中继承出两个或多个子类,用于表示对这种抽象方式的不同实现办法。用了桥接模式之后,我们需要创建两套独立的”类体系”:“抽象体系”定义了我们要执行的操作(比如接口或高层算法),而”实现体系”则包含具体实现方式,抽象体系要调用实体体系以完成其操作。抽象体系中的类会把实现体系中的某个类实例聚合起来,而这个实例将充当抽象接口与具体实现之间的桥梁(bridge)。
本文算是《Python编程实战》的摘要了
#!/usr/bin/env python
# encoding: utf-8
import abc
import os
import re
import tempfile
import Tkinter as tk
def has_methods(*methods):
"""
类修饰器,功能判断*methods是否存在于类中,
使用abc中的__subclasshook__实现
"""
def decorator(Base):
def __subclasshook__(Class, Subclass):
if Class is Base:
needed = set(methods)
for Superclass in Subclass.__mro__:
for meth in needed.copy():
if meth in Superclass.__dict__:
needed.discard(meth)
if not needed:
return True
return NotImplemented
Base.__subclasshook__ = classmethod(__subclasshook__)
return Base
return decorator
@has_methods('initialize', 'draw_caption', 'draw_bar', 'finalize')
class BarRenderer(object):
__metaclass__ = abc.ABCMeta
class BarCharter(object):
def __init__(self, renderer):
if not isinstance(renderer, BarRenderer):
raise TypeError('is not BarCharter')
self.__renderer = renderer
def render(self, caption, pairs):
maximux = max(value for _, value in pairs)
self.__renderer.initialize(len(pairs), maximux)
self.__renderer.draw_caption(caption)
for name, value in pairs:
self.__renderer.draw_bar(name, value)
self.__renderer.finalize()
class TextBarRenderer(object):
def __init__(self, scaleFactor=40):
self.scaleFactor = scaleFactor
def initialize(self, bars, maximum):
assert bars > 0 and maximum > 0
self.scale = self.scaleFactor / maximum
def draw_caption(self, caption):
print("{0:^{2}}\n{1:^{2}}".format(caption, "=" * len(caption),
self.scaleFactor))
def draw_bar(self, name, value):
print("{} {}".format("*" * int(value * self.scale), name))
def finalize(self):
pass
class ImageBarRenderer(object):
COLORS = ('red', 'green','blue', 'yellow', 'magenta', 'cyan')
def __init__(self, stepHeight=10, barWidth=30, barGap=2):
self.stepHeight = stepHeight
self.barWidth = barWidth
self.barGap = barGap
def initialize(self, bars, maximum):
assert bars > 0 and maximum > 0
if tk._default_root is None:
self.gui = tk.Tk()
self.inGui = False
else:
self.gui = tk._default_root
self.inGui = True
self.index = 0
self.width = bars * (self.barWidth + self.barGap)
self.height = maximum * self.stepHeight
self.image = tk.PhotoImage(width=self.width, height=self.height)
self.image.put("white", (0, 0, self.width, self.height))
def draw_caption(self, caption):
self.filename = os.path.join(tempfile.gettempdir(),
re.sub(r"\W+", "_", caption) + ".gif")
def draw_bar(self, name, value):
color = ImageBarRenderer.COLORS[self.index %
len(ImageBarRenderer.COLORS)]
x0 = self.index * (self.barWidth + self.barGap)
x1 = x0 + self.barWidth
y0 = self.height - (value * self.stepHeight)
y1 = self.height - 1
self.image.put(color, (x0, y0, x1, y1))
self.index += 1
def finalize(self):
self.image.write(self.filename, "gif")
print("wrote", self.filename)
if not self.inGui:
self.gui.quit()
def main():
pairs = (('Mon', 16), ('Tue', 17), ('Wed', 19),
('Thu', 22), ('Fri', 24), ('Sat', 21),
('Sun', 19))
textBarCharter = BarCharter(TextBarRenderer())
textBarCharter.render('Forecast 6/8', pairs)
imageBarCharter = BarCharter(ImageBarRenderer())
imageBarCharter.render('Forecase 6/8', pairs)
if __name__ == '__main__':
main()
TextBarRenderer
的finalize()
什么事没做,但还是必须写上,因为条形图渲染器的接口里定义了这个方法
上面代码中尽管TextBarRenderer
与ImageBarRenderer
的实现方式差别很大,但它们均可作为抽象体系与实现体系之间的桥梁。