Jamal的博客

Python设计模式-适配器模式

适配器模式是一种结构性设计模式,帮助我们实现两个不兼容接口之间的兼容。如果我们希望把一个老组件用于一个新系统中,或者把一个新组件用在一个老系统中,不对代码进行任何修改就能通信的情况很少见。但是又不是总是能修改代码,或者因为我们无法访问这个代码,所以修改代码本身就不实际。在这些情况下,我们可以编写一个额外的代码层,该代码层包含让两个接口之间能够通信需要进行的所有修改,这个代码就叫适配器。

电商系统就是这方面的一个好例子。假设我们现在在使用的系统使用的是以人民币为结算单位,现在想支持更多的货币,例如美元,如果我们有系统的代码的话,则可以拓展系统,但是如果我们没有源代码的话,则无法直接修改,解决方案是斜一个适配器将数据从给定的人民币转化成需要的美元格式。
适配器并不仅仅对数据转换有用。通常来说如果你想使用一个接口,期望他是function_a(),但是仅有function_b()可用,那么可以使用一个适配器把function_b()转换(适配)成function_a()。不仅对于函数可以这样做,对于函数参数也可以这样做。

代码实例

代码实例中运用类的内部字典来实现。
我们的应用有一个Computer类,用来显示一台电脑的基本信息:

1
2
3
4
5
6
7
8
9
class Computer:
def __init__(self, name):
self.name = name
def __str__(self):
return "the {} computer".format(self.name)
def execute(self):
return "execute a program"

在这里,execute方法是计算机可以执行的主要动作,这一动作由客户端调用。
我们再新建两个类,这两个类被设定为无法查询源代码的接口:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Human:
def __init__(self, name):
self.name = name
def __str__(self):
return "human {}".format(self.name)
def speak(self):
return "say hello"
class Synthesizer:
def __init__(self, name):
self.name = name
def __str__(self):
return "Synthesizer {}".format(self.name)
def play(self):
return "is playing a song"

Synthesizer中主要动作由play()执行,Human中主要动作由speak()执行。
这里有个问题:客户端仅知道怎么调用execute()方法,并不知道play()和speak(),在不改变Human和Synthesizer类的前提下,我们就可以使用适配器来让代码有效,我们创建一个通用的Adapter类,将一些带不同接口的对象是配到一个统一接口中,init方法中的obj参数是我们想要适配的对象,apapted_methods是一个字典,键值对中的键是客户端要调用的方法,值是应该被调用的方法。

1
2
3
4
5
6
7
class Adapter:
def __init__(self, obj, apapted_methods):
self.obj = obj
self.__dict__.update(apapted_methods)
def __str__(self):
return self.obj.__str__()

下面看使用适配器模式的方法。列表objects容纳着所有对象。属于Computer类的可兼容对象不需要适配,可以直接将他们添加到列表中,不兼容的对象则不能直接添加,使用Adapter类来适配他们,结果是对于所有对象,客户端代码都可以调用已知的execute(0方法,而无需关注被使用的类之间的任何接口差别。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
if __name__ == "__main__":
computer = Computer("hello")
print(computer)
print(computer.__dict__)
objects = [Computer("com1")]
synth = Synthesizer("moon")
human = Human("tom")
adapter1 = Adapter(synth, dict(execute=synth.play))
print(adapter1.__dict__)
adapter2 = Adapter(human, dict(execute=human.speak))
print(adapter2.__dict__)
objects.append(adapter1)
objects.append(adapter2)
print(Adapter.__dict__)
for i in objects:
print("{} {}".format(str(i), i.execute()))