来源:《设计模式 可复用面向对象软件的基础》 ---GoF
结构型模式
1. 适配器
- 起源
有一个已经存在的类,你想使用它,但是它又不符合你的接口规范,所以你需要将其转换成你想要的接口形式。
- 方法
有两种实现方法,一种是继承,一种是组合。
对于C++这样的强类型语言来说,继承需要使用多重继承,因为你必需继承原始类以及要适配的接口,而对于python这种就只需要继承原始类即可。
一般而言,组合会比继承更灵活,而且多重继承也容易踩坑,所以建议用组合形式。
- 代码
class Adaptee(object):
def a_useful_function(self):
pass
class InheritAdapter(Adaptee):
"""继承形式"""
def interface_function(self):
self.a_useful_function()
class CombineAdapter(object):
"""组合形式"""
def __init__(self, adaptee):
self._adaptee = adaptee
def interface_function(self):
self._adaptee.a_useful_function()
- 思想
跟插头转换器一个思想。
2. 桥接
- 起源
如果需要设计一个功能,在windows和linux平台下都能运行,同时还需要支持扩展新平台,扩展新功能,合理的做法是:将实现部分和抽象部分分离,抽象部分定义各个平台的基本操作,实现部分使用抽象接口实现不同的功能。
- 代码
class Window(object):
def __init__(self, imp):
self._imp = imp
def draw_contents(self):
pass
### 抽象部分
class WindowImp(object):
def device_text(self):
pass
def device_bitmap(self):
pass
class XWindowImp(WindowImp):
def device_text(self):
pass
def device_bitmap(self):
pass
### 实现部分
class ApplicationWindow(Window):
def draw_contents(self):
self._imp.device_text()
class IconWindow(Window):
def draw_contents(self):
self._imp.device_bitmap()
- 思想
这里的主要思想就是将一个功能的不同部分剥离开,能够各自独立的扩展。
3. 组合
- 起源
对于又有组件又有组件聚合成的容器的系统,如果用户希望容器和组件一样对待,那么可以为他们提供一个统一的抽象接口。
- 代码
class Equipment(object):
def add(self):
pass
def net_price(self):
return 0
class FloppyDisk(Equipment):
"""组件"""
def net_price(self):
return 1
class CompositeEquipment(Equipment):
"""容器"""
def __init__(self):
self._equipment = []
def add(self, eq):
self._equipment.append(eq)
def net_price(self):
total = 0
for eq in self._equipment:
total += eq.net_price()
return total
- 思想
通过统一接口,降低系统中的类型数量。
装饰
- 起源
如果希望动态的给对象增加一些职责,装饰会比生成子类更加灵活一点。
- 代码
class VisualComponent(object):
def draw():
pass
class TextView(VisualComponent):
"""被装饰的类"""
pass
class Decorator(VisualComponent):
"""装饰类的基类"""
def __init__(self, component):
self._component = component
def draw(self):
self._component.draw()
class BorderDecorator(Decorator):
"""装饰类"""
def __init__(self, component):
self._component = component
def draw(self):
super(BorderDecorator, self).draw()
self.draw_border()
def draw_border(self):
pass
- 注意
- 与适配器结构类似,但装饰不会该表对象的职责。
- 装饰可以视为仅有一个组合的组合,但它的目的不在于对象聚合。
- 装饰并没有改变这个对象本身,而策略会改变对象的内核。
外观
- 起源
为了提高复用度,一般子系统或者组件只会提供最基础的功能,而使用者大部分情况下不会关心这些基础组件,为了降低复杂度,会给使用者提供一个更高层次的易用的对外接口。
享元
- 起源
系统中存在大量相同的细粒度对象,可以使用共享技术有效的降低系统中的对象数量。
- 代码
class GlyphFactory(object):
def __init__(self):
self._character = {}
def create_character(self, char):
c = self._character.get(char)
if c is None:
self._character[char] = c = Character(char)
return c
class Character(object):
"""被共享的对象"""
def __init__(self, char):
self._charcode = char
def draw(self, window, context):
"""这里传入外部状态"""
pass
- 思想
运用享元模式需要区分对象的内部状态与外部状态,外部状态可以在运行时作为参数传递。
- 注意
可以用享元模式来实现状态模式和策略模式。
代理
- 起源
控制对对象的访问,有远程代理,虚代理,保护代理等。
- 代码
class Image(object):
def __init__(self, filename):
pass
def draw(self):
pass
class ImageProxy(object):
"""保护代理,惰性加载对象"""
def __init__(self, filename):
self._filename = filename
self._image = None
def get_image(self):
if not self._image:
self._image = Image(self._filename)
return self._image
def draw(self):
self.get_image().draw()
- 注意
代理模式的结构和适配器模式以及装饰模式很像,但他们的目的是不一样的,适配器是为了提供不一样的接口,装饰模式是为了提供额外的功能,代理模式是为了控制对对象的访问。