一、适配器模式
适配器模式可以帮我们实现两个(或更多)不兼容接口之间的兼容。
先看一个简单的示例,实现两家公司获取员工信息接口的兼容:
class ACpnStaff:
name=""
id=""
phone=""
def __init__(self,id):
self.id=id
def getName(self):
print "A protocol getName method...id:%s"%self.id
return self.name
def setName(self,name):
print "A protocol setName method...id:%s"%self.id
self.name=name
def getPhone(self):
print "A protocol getPhone method...id:%s"%self.id
return self.phone
def setPhone(self,phone):
print "A protocol setPhone method...id:%s"%self.id
self.phone=phone
class BCpnStaff:
name=""
id=""
telephone=""
def __init__(self,id):
self.id=id
def get_name(self):
print "B protocol get_name method...id:%s"%self.id
return self.name
def set_name(self,name):
print "B protocol set_name method...id:%s"%self.id
self.name=name
def get_telephone(self):
print "B protocol get_telephone method...id:%s"%self.id
return self.telephone
def set_telephone(self,telephone):
print "B protocol get_name method...id:%s"%self.id
self.telephone=telephone
为在A公司平台复用B公司接口,直接调用B公司人员接口是个办法,但会对现在业务流程造成不确定的风险。为减少耦合,规避风险,我们需要一个帮手,就像是转换电器电压的适配器一样,这个帮手就是协议和接口转换的适配器。适配器构造如下:
class CpnStaffAdapter:
b_cpn=""
def __init__(self,id):
self.b_cpn=BCpnStaff(id)
def getName(self):
return self.b_cpn.get_name()
def getPhone(self):
return self.b_cpn.get_telephone()
def setName(self,name):
self.b_cpn.set_name(name)
def setPhone(self,phone):
self.b_cpn.set_telephone(phone)
适配器将B公司人员接口封装,而对外接口形式与A公司人员接口一致,达到用A公司人员接口访问B公司人员信息的效果。
业务示例如下:
if __name__=="__main__":
acpn_staff=ACpnStaff("123")
acpn_staff.setName("X-A")
acpn_staff.setPhone("10012345678")
print("A Staff Name:%s"%acpn_staff.getName())
print("A Staff Phone:%s"%acpn_staff.getPhone())
bcpn_staff=CpnStaffAdapter("456")
bcpn_staff.setName("Y-B")
bcpn_staff.setPhone("99987654321")
print("B Staff Name:%s"%bcpn_staff.getName())
print("B Staff Phone:%s"%bcpn_staff.getPhone())
再来看一个复杂的示例:
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!!!
二、适配器模式的优点和使用场景
优点:
1、适配器模式可以让两个接口不同,甚至关系不大的两个类一起运行;
2、提高了类的复用度,经过“伪装”的类,可以充当新的角色;
3、适配器可以灵活“拆卸”。
应用场景:
1、不修改现有接口,同时也要使该接口适用或兼容新场景业务中,适合使用适配器模式。例如,在一个嵌入式系统中,原本要将数据从Flash读入,现在需要将数据从磁盘读入,这种情况可以使用适配器模式,将从磁盘读入数据的接口进行“伪装”,以从Flash中读数据的接口形式,从磁盘读入数据。
三、适配器模式的缺点
1、适配器模式与原配接口相比,毕竟增加了一层调用关系,所以,在设计系统时,不要使用适配器模式。