python通过__getattr()__实现Adapter模式对象版本
Adapter模式简介
本文参考链接:https://blog.csdn.net/poppick/article/details/51038800
- 意图
将一个类的接口转化成客户希望的另一个接口。 Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
适配器模式,即定义一个包装类,用于包装不兼容接口的对象 - 动机
把一个类的接口变换成客户端所期待的另一种接口,从而使原本接口不匹配而无法一起工作的两个类能够在一起工作。
1.1 adapter模式的类版本:新adapter类依赖继承已有类,通过多重继承调用已有类中的方法实现接口需求。
1.2 adapter模式的对象版本:将已有类作为新adapter类的成员变量,调用他的方法实现接口需求。 - 适用性
- 你想使用一个已经存在的类, 而他的接口不符合你的需求
- 你想创建一个可以复用的类, 该类可以与其它不相关的类或者可能还没有实现的类协同工作
- 有很多子类, 你没法一一去匹配它们, 这时你可以创建一个adapter类去适配它们的父类接口(对象Adapter版本)
- 可能会有一系列类似的接口, 它们拥有不同的使用条件。 我们可以创建一个wrapper, 根据不同条件调用不同的接口, 从而只对使用者暴露出一个统一的接口
- 双向适配器: 考虑一种情况, 一边是面向对象的前端程序, 一边是进行运算的后端程序,那么很可能需要一个adapter, 将前端的数据适配给后端, 再将后端得出的结果适配给前端
- 可插入的适配器: 一个实现可能有多个调用者, 它们的调用接口各不相同, 这时就需要一个adapter来进行适配
- 关键点
其关键点在于隐藏: 不改变调用者(client)和实现者(adaptee)的代码, 用适配器(adapter)去隐藏它们之间接口的差异, 使它们能协同工作。
python adapter实例
- 实例一
class A(object):
def test(self):
print "A test"
class B(object):
def __init__(self):
self.b = 100
self.A = A()
def __getattr__(self, name):
return getattr(self.A, name)
b = B()
print b.b
b.test()
输出结果
100
A test
这个实例简单解释了作为adapter类的B通过其成员变量获取adaptee类A的接口,实现了在不使用继承的前提下调用A.test()
import os
class Dog(object):
def __init__(self):
self.name = "Dog"
def bark(self):
return "woof!"
class Cat(object):
def __init__(self):
self.name = "Cat"
def meow(self):
return "meow!"
class Human(object):
def __init__(self):
self.name = "Human"
def speak(self):
return "'hello'"
class Car(object):
def __init__(self):
self.name = "Car"
def make_noise(self, octane_level):
return "vroom%s" % ("!" * octane_level)
class Adapter(object):
"""
Adapts an object by replacing methods.
Usage:
dog = Dog
dog = Adapter(dog, dict(make_noise=dog.bark))
"""
def __init__(self, obj, adapted_methods):
"""We set the adapted methods in the object's dict"""
self.obj = obj
self.__dict__.update(adapted_methods)
def __getattr__(self, attr):
"""All non-adapted calls are passed to the object"""
return getattr(self.obj, attr)
def main():
objects = []
dog = Dog()
objects.append(Adapter(dog, dict(make_noise=dog.bark)))
cat = Cat()
objects.append(Adapter(cat, dict(make_noise=cat.meow)))
human = Human()
objects.append(Adapter(human, dict(make_noise=human.speak)))
car = Car()
car_noise = lambda: car.make_noise(3)
objects.append(Adapter(car, dict(make_noise=car_noise)))
for obj in objects:
print("A", obj.name, "goes", obj.make_noise())
if __name__ == "__main__":
main()
A Dog goes woof!
A Cat goes meow!
A Human goes 'hello'
A Car goes vroom!!!
- 实例三
在使用__getattr(self, name)__的过程中可以通过adapter类中的__init(self, classname)__的形式提前将本次指向的adaptee类确定。
class adapterA(object):
def __init__(self, classname):
self.classname = classname
...
def __getattr(self, name):
return getattr(ClassDict.get(self.classname, baseClass)(self), name)
# 解释说明 ClassDict中提前存入不同的adaptee类名,这样可以通过实例化adapterA时指定adaptee类,
# 并有指向的调用接口, baseClass为假设的基类包含所有接口避免traceback。
# 这样实现的好处是不需要提前实例化adaptee类