五分钟就能学会的适配器模式,告别多个上游的烦恼

2021-01-07 10:37:13 浏览数 (2)

大家好,今天给大家介绍Adapter模式,即适配器模式。

说到适配器大家可能想到的都是充电器以及各种电器的电源,其实适配器还有一层含义是电源的转接器。比如下图的东西在英文当中也叫做Adapter。我们这里说的适配器的含义就是指的这个。

为什么需要适配器?

我们为什么需要适配器呢?其实和现实中的原因是一样的,因为接口不匹配。大家有经历过跨国旅行的话,应该都知道现在国际上的插座分为好几个标准,有英式插座,也有美式插座,还有欧式插座。不同种类的插座之间不能互相通用,这样就很难受,如果没有适配器做中转的话,我们的电器都没有办法正常使用。

同理,在代码当中也是一样的,比如首页展示的商品有好几个源头,有些来源于广告系统,有些来源于推荐系统,还有些是运营手动配的,来源于投放系统。但是由于历史原因,这些接口的格式也都不相同,那么对于使用者来说就非常蛋疼,我们需要手动去适配这些接口, 这样导致的结果就是写出来的代码比较丑而且还冗长,不利于维护。

所以这里有一个解决方案就是通过适配器来适配不同的接口,这样我们就可以通过同一个接口来调用所有不同的方法。

代码实现

Adapter的代码实现也非常简单,也属于看完代码就会使用的典型。

代码语言:javascript复制
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的时候,只需要通过默认参数的方法传入我们需要适配的方法名即可。这里举个例子:

代码语言:javascript复制
adapter = Adapter(obj, getElement=lambda x: x['abc']   3)

由于我们在__getattr__方法当中做了映射,这样我们直接调用adapter.getElement()就可以生效。

最后我们来看一个完整的例子:

代码语言:javascript复制
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模式也是一种自底向上进行抽象的模式,和之前介绍的委托模式有一点类似,两者的底层原理是一样的,只是实现的方法略有不同。其实落实到我们最终项目当中的设计模式是怎样的并不太重要,因为设计模式天然就是拿来用的,相比于是否严格遵守了某一种模式,更加贴近使用者的诉求更加重要。所以大家不必太过在意形式,哪怕最终写出来有一点四不像也没有关系,只要能够实际解决问题,为开发带来便利就好。

0 人点赞