大家好,今天给大家介绍Adapter模式,即适配器模式。
说到适配器大家可能想到的都是充电器以及各种电器的电源,其实适配器还有一层含义是电源的转接器。比如下图的东西在英文当中也叫做Adapter。我们这里说的适配器的含义就是指的这个。
我们为什么需要适配器呢?其实和现实中的原因是一样的,因为接口不匹配。大家有经历过跨国旅行的话,应该都知道现在国际上的插座分为好几个标准,有英式插座,也有美式插座,还有欧式插座。不同种类的插座之间不能互相通用,这样就很难受,如果没有适配器做中转的话,我们的电器都没有办法正常使用。
同理,在代码当中也是一样的,比如首页展示的商品有好几个源头,有些来源于广告系统,有些来源于推荐系统,还有些是运营手动配的,来源于投放系统。但是由于历史原因,这些接口的格式也都不相同,那么对于使用者来说就非常蛋疼,我们需要手动去适配这些接口, 这样导致的结果就是写出来的代码比较丑而且还冗长,不利于维护。
所以这里有一个解决方案就是通过适配器来适配不同的接口,这样我们就可以通过同一个接口来调用所有不同的方法。
Adapter的代码实现也非常简单,也属于看完代码就会使用的典型。
class Adapter:
def __init__(self, obj, **adapted_methods):
self.obj = obj
self.__dict__.update(adapted_methods)
def __getattr__(self, attr):
return getattr(self.obj, attr)
def original_dict(self):
return self.obj.__dict__
如果我们忽略最后一个origin_dict方法的话,它只有两个方法,一共3行代码。我们着重看下init方法,当中其实只有一个逻辑,就是从外界传入一个叫做adapted_methods的dict,然后会将这个dict更新到Adapter本身。我们都知道在Python当中传参的时候,如果我们以默认参数的形式传参,实际上都会被转化成dict的形式。所以看起来传入的是一个dict,实际上只是一些默认形式传入的参数而已。
也就是说我们在初始化Adaptor的时候,只需要通过默认参数的方法传入我们需要适配的方法名即可。这里举个例子:
adapter = Adapter(obj, getElement=lambda x: x['abc'] + 3)
由于我们在__getattr__
方法当中做了映射,这样我们直接调用adapter.getElement()就可以生效。
最后我们来看一个完整的例子:
class Dog:
def __init__(self):
self.name = 'Dog'
def bark(self):
return 'woof'
class Cat:
def __init__(self):
self.name = 'Cat'
def meow(self):
return 'meow'
class Human:
def __init__(self):
self.name = 'Human'
def speak(self):
return "'hello'"
class Car:
def __init__(self):
self.name = 'Car'
def make_noise(self, octane_level):
return 'vroom{0}'.format("!" * octane_level)
class Adapter:
def __init__(self, obj, **adapted_methods):
self.obj = obj
self.__dict__.update(adapted_methods)
def __getattr__(self, attr):
return getattr(self.obj, attr)
def original_dict(self):
return self.obj.__dict__
if __name__ == '__main__':
objects = []
dog = Dog()
cat = Cat()
human = Human()
car = Car()
objects.append(Adapter(dog, make_noise=dog.bark))
objects.append(Adapter(cat, make_noise=cat.meow))
objects.append(Adapter(human, make_noise=human.speak))
objects.append(Adapter(car, make_noise=lambda: car.make_noise(3)))
for obj in objects:
print('A {0} goes {1}'.format(obj.name, obj.make_noise()))
在这个例子当中,我们实现了几种会发出声音的类,比如狗、猫、人、汽车等等。但是不同的事物发出声音的方式是不同的,比如人类就是说话,汽车则是鸣笛,猫和狗也都有各自的叫声。我们单独使用这些类当然是没有问题,但如果我们希望通过一种方式能够统一调用就做不到了。所以这里才引入了Adapter类,作为中转,这样就可以通过一个数组来遍历调用所有的实例,即使它们的方法名和参数都不相同。
Adapter模式也是一种自底向上进行抽象的模式,和之前介绍的委托模式有一点类似,两者的底层原理是一样的,只是实现的方法略有不同。其实落实到我们最终项目当中的设计模式是怎样的并不太重要,因为设计模式天然就是拿来用的,相比于是否严格遵守了某一种模式,更加贴近使用者的诉求更加重要。所以大家不必太过在意形式,哪怕最终写出来有一点四不像也没有关系,只要能够实际解决问题,为开发带来便利就好。