> 文章列表 > 不得不说的结构型模式-适配器模式

不得不说的结构型模式-适配器模式

不得不说的结构型模式-适配器模式

适配器模式(Adapter Pattern)是结构型模式之一,它将一个类的接口转换成客户希望的另一个接口,从而使原本由于接口不兼容而不能一起工作的类能够协同工作。适配器模式包括对象适配器和类适配器两种实现方式。

 

在对象适配器中,适配器通过包装一个需要适配的对象来实现接口转换,它将需要适配的对象作为成员变量,同时实现目标接口。在客户端调用目标接口时,适配器会将调用委托给被适配的对象,并根据需要进行接口转换和适配。在类适配器中,适配器通过多重继承来实现接口转换,它继承需要适配的类和目标接口,同时重写目标接口中的方法来实现接口转换。

以下是一个使用对象适配器实现的适配器模式的示例代码:

// 需要适配的接口
class ITarget {
public:virtual void Request() = 0;
};// 需要适配的类
class Adaptee {
public:void SpecificRequest() {std::cout << "Adaptee::SpecificRequest()" << std::endl;}
};// 对象适配器
class Adapter : public ITarget {
public:Adapter(Adaptee* adaptee) : m_adaptee(adaptee) {}virtual void Request() override {std::cout << "Adapter::Request()" << std::endl;m_adaptee->SpecificRequest();}private:Adaptee* m_adaptee;
};int main() {Adaptee* adaptee = new Adaptee();ITarget* target = new Adapter(adaptee);target->Request();delete target;delete adaptee;return 0;
}

在这个示例代码中,我们需要将Adaptee类的SpecificRequest()方法适配成ITarget接口的Request()方法,我们定义了ITarget接口和Adaptee类,并在Adapter类中通过包装Adaptee对象来实现接口转换。在客户端中,我们通过创建Adaptee对象和Adapter对象,然后将Adapter对象传递给客户端,客户端就可以调用目标接口Request()方法来访问Adaptee对象的SpecificRequest()方法了。

适配器模式的实际应用非常广泛,例如在新旧系统的数据交换中,可能需要将一种数据格式转换成另一种数据格式,可以使用适配器模式来实现;在使用第三方库时,可能需要将第三方库的接口转换成自己的接口,可以使用适配器模式来实现;在复用旧代码时,可能需要将旧代码的接口转换成新的接口,可以使用适配器模式来实现。通过使用适配器模式,我们可以

复用现有代码和接口,避免修改原有代码和接口,从而减少风险。

适配器模式的好处包括:

  1. 适配器模式可以让两个原本不兼容的接口能够协同工作,提高代码的复用性和可维护性;
  2. 适配器模式可以避免修改原有的代码和接口,从而减少风险和工作量;
  3. 适配器模式可以将适配的代码和接口与客户端代码解耦,提高代码的灵活性和可扩展性。

适配器模式的缺点包括:

  1. 适配器模式可能会增加代码的复杂度,特别是在涉及多个适配器的情况下;
  2. 适配器模式可能会影响代码的性能,因为需要进行接口转换和适配;
  3. 适配器模式可能会隐藏原有代码和接口的缺陷和问题,需要谨慎使用。

适配器模式是一种非常有用的结构型设计模式,可以将两个不兼容的接口协同工作,提高代码的复用性和可维护性,同时也需要注意其可能带来的复杂度和性能问题。

下面我们用 C++ 代码来实现一个简单的适配器模式示例。

首先,我们定义一个目标接口 Target,包含一个输出字符串的纯虚函数 output()

class Target {
public:virtual ~Target() = default;virtual void output() const = 0;
};

接下来,我们定义一个已有的类 Adaptee,其中包含一个输出整数的函数 outputInteger()

class Adaptee {
public:void outputInteger() const {std::cout << "Output integer: " << 42 << std::endl;}
};

为了让 Adaptee 类能够与 Target 接口兼容,我们需要定义一个适配器类 Adapter,并继承自 Target 接口,同时包含一个指向 Adaptee 对象的指针:

class Adapter : public Target {
public:Adapter(const Adaptee* adaptee): m_adaptee(adaptee) {}virtual void output() const override {m_adaptee->outputInteger();}private:const Adaptee* m_adaptee;
};

在适配器的 output() 函数中,我们将调用 Adaptee 类的 outputInteger() 函数来实现输出整数的功能。

最后,我们可以通过如下代码来测试适配器模式的效果:

int main() {Adaptee adaptee;Target* target = new Adapter(&adaptee);target->output();delete target;return 0;
}

在这段测试代码中,我们首先创建了一个 Adaptee 类对象 adaptee,然后将其作为参数传递给了一个 Adapter 类对象 adapter,接着将 adapter 对象指针强制转换为 Target 接口指针,并通过该指针调用了 output() 函数。在运行时,output() 函数会调用 Adaptee 类的 outputInteger() 函数,最终输出整数 42。

总之,适配器模式可以帮助我们解决两个不兼容的接口之间的问题,提高代码的复用性和可维护性。在实际应用中,适配器模式经常被用于系统集成和接口转换等场景。