Python实现软件设计模式7:适配器模式 Adapter Pattern
动机
有两个不存在直接继承或关联关系的类A、B, A希望能利用到B类中某个已存在的、功能完善的方法,而不再去具体实现A的接口源码;适配器模式使接口不兼容的那些类可以一起工作。
主要角色
- 目标类 Target 抽象接口类
- 适配者 Adaptee
- 适配器 Adapter 具体实现接口
- 客户端 Client
客户端针对目标类编程,希望调用目标类的某个方法;而适配者中已经提供了关于Target中该方法的完整实现。
分类
具体分为两种类型,类适配器、对象适配器(使用频率更高、更灵活)
- 类适配器: Target与Adapter是继承关系,Adapter与Adaptee也是继承关系。由于语法的限制,有些语言中一个类只能单继承一个父类,所以类适配器可能不太适合使用;并且即使能多继承、假设适配多个父类这样也不太好扩展。
public class Adapter extends Adaptee implements Target{
public void request(){
super.specificRequest();
}
}
- 对象适配器: Target与Adapter是继承关系,然而Adapter与Adaptee之间是委派关系(在Adapter中定义一个Adaptee的对象)。对象适配器的Java版本伪代码如下:
public class Adapter extends Target{
private Adaptee adaptee; // 委派一个对象
public Adapter(Adaptee x){
this.adaptee = x;
}
public void request(){
adaptee.specificRequest();
}
}
案例:仿生机器人
需要设计一个可以模拟各种动物行为的机器人,在机器人中定义一系列方法,如叫喊cry、移动move;如果已存在一个狗的类,其中已经定义了功能类似的wang和run方法;
Python版本代码
from abc import ABC,abstractmethod
class Robot(ABC):
@abstractmethod
def cry(self):
pass
@abstractmethod
def move(self):
pass
class Dog:
def wang(self):
print("狗儿_wang wang wang!")
def run(self):
print("狗儿_run run run!")
class Bird:
def tweedle(self):
print("鸟儿_ji ji ji!")
def fly(self):
print("鸟儿_fly fly fly!")
# 对象适配1
class DogAdapter(Robot): # 让机器人适配狗特性的适配器类
def __init__(self):
self.__adaptee = Dog()
def cry(self):
print("机器人模仿狗的叫喊:")
self.__adaptee.wang()
def move(self):
print("机器人模仿狗的移动:")
self.__adaptee.run()
# 对象适配2
class BirdAdapter(Robot): # 让机器人适配狗特性的适配器类
def __init__(self):
self.__adaptee = Bird()
def cry(self):
print("机器人模仿鸟的叫喊:")
self.__adaptee.tweedle()
def move(self):
print("机器人模仿鸟的移动:")
self.__adaptee.fly()
class Client:
def __init__(self, AdapterName):
self.Adapter = AdapterName
def run(self):
try:
robot = eval(self.Adapter)()
robot.cry()
robot.move()
except NameError:
print(f"Error! Robot adapter '{self.Adapter}' doesn't exits...")
if __name__ == '__main__':
rb1 = Client('DogAdapter')
rb1.run()
print()
rb2 = Client('BirdAdapter')
rb2.run()
总结
优点
- 将目标类与适配者类解耦,通过引入一个适配器来重用现有的适配者类,无需修改原有的结构
- 增加了类的透明性和复用性,提高了适配者的复用性,同一个适配者类可以再多个不同的系统中复用
- 灵活性和扩展性好
- 类适配器模式:置换一些适配者的方法很方便
- 对象适配器模式:可以把多个不同的适配者适配(委派)到同一个目标
缺点
-
类适配器模式:一次最多智能适配一个适配者类,不可以适配多个适配者;Java语义下的目标抽象类只能声明为接口,不能为类;Java语义下的适配者类不能为final类(因为final类不能有子类)
-
对象适配器模式:适配器中置换适配者类的某些方法比较麻烦