结构性设计模式提出了一种创建新功能的对象的组合方式。
适配器模式是一种结构性设计模式,它帮助我们使两个不兼容的接口兼容。如果我们想在新的系统中使用旧的组件,或者我们想在旧系统中使用新的组件,通常需要改变代码适配。但是改代码未必科兴,要么是因为我们没有权限,要么是因为这不切实际。我们可以编写额外的层来实现两个接口之间的通信做所有需要的修改。这个层被称为适配器。
真实世界的例子
当你从大多数欧洲国家到英国或美国旅行时,或者反过来,你需要使用一个插头适配器为你的笔记本电脑充电。将一些设备连接到您的计算机也需要同样的适配器:USB适配器。
在软件类别中,Zope应用服务器(http://www.zope.org)因其Zope组件架构(ZCA)而闻名,它贡献了几个大型Python网络项目使用的接口和适配器的实现。由前Zope开发者建立的Pyramid是一个Python网络框架,它从Zope中吸取了好的想法,为开发网络应用提供了更多的模块化方法。Pyramid使用适配器,使现有的对象有可能符合特定的API,而不需要修改它们。另一个来自Zope生态系统的项目,Plone CMS,在引擎盖下使用适配器。
实例
俱乐部的活动,主要是通过雇佣有天赋的艺术家来组织表演和活动,供客户娱乐。
有一个俱乐部类,它代表俱乐部,雇佣的艺术家在晚上进行表演。organize_performance()方法是俱乐部可以执行的主要动作。代码如下。
class Club:
def __init__(self, name):
self.name = name
def __str__(self):
return f'the club {self.name}'
def organize_event(self):
return 'hires an artist to perform for the people'
多数俱乐部会雇佣一个DJ来表演,但我们的应用程序解决了组织多样化表演的需要,如音乐家或乐队、舞蹈家、单人或独角戏等等。
我们找到了一个开源的贡献库,它给我们带来了两个有趣的类Musician和Dancer。在Musician类中,主要的动作是由play()方法完成的。在Dancer类中,它是由dance()方法来执行的。
在我们的例子中,为了表明这两个类是外部的,我们把它们放在一个单独的模块中。音乐家类的代码如下。
class Musician:
def __init__(self, name):
self.name = name
def __str__(self):
return f'the musician {self.name}'
def play(self):
return 'plays music'
class Dancer:
def __init__(self, name):
self.name = name
def __str__(self):
return f'the dancer {self.name}'
def dance(self):
return 'does a dance performance'
客户端代码只知道如何调用Club类的organ_performance()方法,不知道play()或dance()。
我们怎样才能在不改变Musician和Dancer的情况下使代码工作呢?
我们创建了一个通用的适配器类,它允许我们将一些具有不同接口的对象改编成一个统一的接口。init()方法的obj参数是我们想要适配的对象,而advert_methods是包含键/值对的字典,匹配客户端调用的方法和应该被调用的方法。
适配器类的代码如下。
class Adapter:
def __init__(self, obj):
self.obj = obj
adapted_methods = None
if hasattr(obj, 'play') or hasattr(obj, 'dance'):
if hasattr(obj, 'play'):
adapted_methods = dict(organize_event=obj.play)
elif hasattr(obj, 'dance'):
adapted_methods = dict(organize_event=obj.dance)
self.__dict__.update(adapted_methods)
def __str__(self):
return str(self.obj)
Club类的兼容对象不需要适应,不兼容的对象需要适配,使用适配器类。
客户端代码可以继续在所有对象上使用已知的organ_performance()方法,而不需要意识到所用类之间的任何接口差异。
def main():
objects = [Club('Jazz Cafe'), Musician('Roy Ayers'), Dancer('Shane Sparks')]
for obj in objects:
if hasattr(obj, 'play') or hasattr(obj, 'dance'):
# referencing the adapted object here
obj = Adapter(obj)
print(f'{obj} {obj.organize_event()}')
小结
本章介绍了适配器的设计模式。我们使用适配器模式来使两个(或多个)不兼容的接口兼容。我们每天都在使用适配器,用于设备的互连、充电等等。
适配器使事情在实现后能够正常运行。Pyramid网络框架、Plone CMS和其他基于Zope或相关的框架都使用适配器模式来实现接口的兼容性。
在实现部分,我们看到了如何使用适配器模式实现接口的一致性,而不需要修改不兼容的模型的源代码。这是通过一个用的Adapter类来实现的,它为我们做了这些工作。
网友评论