Python实现软件设计模式7:适配器模式 Adapter Pattern

发布时间 2024-01-11 12:28:43作者: 爱吃砂糖橘的白龙

动机

有两个不存在直接继承或关联关系的类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类不能有子类)

  • 对象适配器模式:适配器中置换适配者类的某些方法比较麻烦